Mi sono incuriosito e ho controllato il link di Adam Backstrom a Tech Your Universe . Questo articolo descrive uno dei motivi che richiedono di essere utilizzato al posto di require_once. Tuttavia, le loro affermazioni non sono state all'altezza della mia analisi. Sarei interessato a vedere dove avrei potuto analizzare male la soluzione. Ho usato PHP 5.2.0 per i confronti.
Ho iniziato creando 100 file di intestazione che utilizzavano request_once per includere un altro file di intestazione. Ognuno di questi file sembrava simile a:
<?php
// /home/fbarnes/phpperf/hdr0.php
require_once "../phpperf/common_hdr.php";
?>
Li ho creati usando un rapido hack di Bash:
for i in /home/fbarnes/phpperf/hdr{00..99}.php; do
echo "<?php
// $i" > $i
cat helper.php >> $i;
done
In questo modo potrei facilmente scambiare tra l'utilizzo di request_once e Require quando si includono i file di intestazione. Ho quindi creato un app.php per caricare i cento file. Questo sembrava:
<?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);
?>
Ho contrastato le intestazioni Require_once con le intestazioni Require che utilizzavano un file di intestazione simile a:
<?php
// /home/fbarnes/phpperf/h/hdr0.php
if(!defined('CommonHdr'))
{
require "../phpperf/common_hdr.php";
define('CommonHdr', 1);
}
?>
Non ho trovato molta differenza quando eseguivo questo con request vs. Require_once. In effetti, i miei test iniziali sembravano implicare che un requisito era leggermente più veloce, ma non ci credo necessariamente. Ho ripetuto l'esperimento con 10000 file di input. Qui ho visto una differenza consistente. Ho eseguito il test più volte, i risultati sono vicini ma l'utilizzo di request_once utilizza in media 30,8 jiffie utente e 72,6 jiffie di sistema; l'utilizzo richiede utilizza in media 39,4 jiffies utente e 72,0 jiffies di sistema. Pertanto, sembra che il carico sia leggermente più basso usando request_once. Tuttavia, il tempo dell'orologio a muro è leggermente aumentato. Le 10.000 chiamate request_once utilizzano in media 10,15 secondi per il completamento e 10.000 chiamate in media richiedono 9,84 secondi.
Il prossimo passo è esaminare queste differenze. Ho usato strace per analizzare le chiamate di sistema che vengono effettuate.
Prima di aprire un file da request_once vengono effettuate le seguenti chiamate di sistema:
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
Questo contrasta con richiede:
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 implica che require_once dovrebbe effettuare più chiamate lstat64. Tuttavia, entrambi effettuano lo stesso numero di chiamate lstat64. Forse, la differenza è che non sto eseguendo APC per ottimizzare il codice sopra. Tuttavia, successivamente ho confrontato l'output di strace per le intere esecuzioni:
[fbarnes@myhost phpperf]$ wc -l strace_1000r.out strace_1000ro.out
190709 strace_1000r.out
210707 strace_1000ro.out
401416 total
In effetti, ci sono circa altre due chiamate di sistema per file di intestazione quando si utilizza require_once. Una differenza è che require_once ha una chiamata aggiuntiva alla funzione time ():
[fbarnes@myhost phpperf]$ grep -c time strace_1000r.out strace_1000ro.out
strace_1000r.out:20009
strace_1000ro.out:30008
L'altra chiamata di sistema è getcwd ():
[fbarnes@myhost phpperf]$ grep -c getcwd strace_1000r.out strace_1000ro.out
strace_1000r.out:5
strace_1000ro.out:10004
Questo si chiama perché ho deciso il percorso relativo a cui si fa riferimento nei file hdrXXX. Se lo faccio come riferimento assoluto, l'unica differenza è la chiamata di tempo aggiuntivo (NULL) effettuata nel codice:
[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
Ciò sembra implicare che è possibile ridurre il numero di chiamate di sistema utilizzando percorsi assoluti anziché percorsi relativi. L'unica differenza al di fuori di questo è il tempo (NULL) chiamate che sembrano essere utilizzate per strumentare il codice per confrontare ciò che è più veloce.
Un'altra nota è che il pacchetto di ottimizzazione APC ha un'opzione chiamata "apc.include_once_override" che afferma che riduce il numero di chiamate di sistema effettuate dalle chiamate request_once e include_once (consultare la documentazione di PHP ).