Ich wurde neugierig und überprüfte Adam Backstroms Link zu Tech Your Universe . Dieser Artikel beschreibt einen der Gründe, warum require anstelle von require_once verwendet werden sollte. Ihre Behauptungen hielten meiner Analyse jedoch nicht stand. Es würde mich interessieren, wo ich die Lösung möglicherweise falsch analysiert habe. Ich habe PHP 5.2.0 für Vergleiche verwendet.
Ich begann damit, 100 Header-Dateien zu erstellen, die require_once verwendeten, um eine weitere Header-Datei einzuschließen. Jede dieser Dateien sah ungefähr so aus:
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
Ich habe diese mit einem schnellen Bash-Hack erstellt:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
Auf diese Weise konnte ich leicht zwischen require_once und require wechseln, wenn ich die Header-Dateien einbezog. Ich habe dann eine app.php erstellt, um die hundert Dateien zu laden. Das sah so aus:
<?php
// Load all of the php hdrs that were created previously
for($i=0; $i < 100; $i++)
{
require_once "/home/fbarnes/phpperf/hdr$i.php";
}
// Read the /proc file system to get some simple stats
$pid = getmypid();
$fp = fopen("/proc/$pid/stat", "r");
$line = fread($fp, 2048);
$array = split(" ", $line);
// Write out the statistics; on RedHat 4.5 with kernel 2.6.9
// 14 is user jiffies; 15 is system jiffies
$cntr = 0;
foreach($array as $elem)
{
$cntr++;
echo "stat[$cntr]: $elem\n";
}
fclose($fp);
?>
Ich habe die Header require_once den Headern require_ gegenübergestellt, die eine Header-Datei verwendet haben, die wie folgt aussieht:
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
Ich habe keinen großen Unterschied festgestellt, als ich dies mit require vs. require_once ausgeführt habe. Tatsächlich schienen meine ersten Tests zu implizieren, dass require_once etwas schneller war, aber ich glaube das nicht unbedingt. Ich habe das Experiment mit 10000 Eingabedateien wiederholt. Hier habe ich einen konsequenten Unterschied gesehen. Ich habe den Test mehrmals ausgeführt. Die Ergebnisse sind nahe beieinander, aber bei Verwendung von require_once werden durchschnittlich 30,8 Benutzer-Jiffies und 72,6 System-Jiffies verwendet. Die Verwendung erfordert durchschnittlich 39,4 Benutzer-Jiffies und 72,0 System-Jiffies. Daher scheint die Last mit require_once etwas geringer zu sein. Die Wanduhrzeit ist jedoch leicht erhöht. Die 10.000 erforderlichen Anrufe benötigen durchschnittlich 10,15 Sekunden, und die 10.000 erforderlichen Anrufe benötigen durchschnittlich 9,84 Sekunden.
Der nächste Schritt besteht darin, diese Unterschiede zu untersuchen. Ich habe strace verwendet , um die Systemaufrufe zu analysieren, die gerade getätigt werden.
Vor dem Öffnen einer Datei aus require_once werden folgende Systemaufrufe ausgeführt:
time(NULL) = 1223772434
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=88, ...}) = 0
time(NULL) = 1223772434
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
Dies steht im Gegensatz zu erfordern:
time(NULL) = 1223772905
lstat64("/home", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf", {st_mode=S_IFDIR|0755, st_size=4096, ...}) = 0
lstat64("/home/fbarnes/phpperf/h", {st_mode=S_IFDIR|0755, st_size=270336, ...}) = 0
lstat64("/home/fbarnes/phpperf/h/hdr0.php", {st_mode=S_IFREG|0644, st_size=146, ...}) = 0
time(NULL) = 1223772905
open("/home/fbarnes/phpperf/h/hdr0.php", O_RDONLY) = 3
Tech Your Universe impliziert, dass require_once mehr lstat64-Aufrufe tätigen sollte. Beide führen jedoch die gleiche Anzahl von lstat64-Aufrufen durch. Möglicherweise besteht der Unterschied darin, dass ich APC nicht ausführe, um den obigen Code zu optimieren. Als nächstes verglich ich jedoch die Strace-Ausgabe für die gesamten Läufe:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
Tatsächlich gibt es bei Verwendung von require_once ungefähr zwei weitere Systemaufrufe pro Header-Datei. Ein Unterschied besteht darin, dass require_once einen zusätzlichen Aufruf der Funktion time () hat:
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
Der andere Systemaufruf ist getcwd ():
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
Dies wird aufgerufen, weil ich mich für einen relativen Pfad entschieden habe, auf den in den hdrXXX-Dateien verwiesen wird. Wenn ich dies zu einer absoluten Referenz mache, ist der einzige Unterschied der zusätzliche Zeitaufruf (NULL) im Code:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190705 strace_1000r.out
200705 strace_1000ro.out
391410 total
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20008
strace_1000ro.out:30008
Dies scheint zu implizieren, dass Sie die Anzahl der Systemaufrufe reduzieren können, indem Sie absolute Pfade anstelle relativer Pfade verwenden. Der einzige Unterschied besteht in den Zeitaufrufen (NULL), die anscheinend zur Instrumentierung des Codes verwendet werden, um zu vergleichen, was schneller ist.
Ein weiterer Hinweis ist, dass das APC-Optimierungspaket eine Option namens "apc.include_once_override" enthält, die behauptet, dass es die Anzahl der Systemaufrufe reduziert, die von den Aufrufen require_once und include_once ausgeführt werden (siehe PHP-Dokumentation ).