PHP futástesztek, avagy a PHP benchmark
PHP-ban írt forráskódjaink futási idejét sokban befolyásolja a szerver sebessége, a php verzószáma és a megírt kódban felhasznált függvények fehasználási módja. Az összehasonlításban mért időegységek más-más tesztkörnyezetben eltérhetnek, de az arányok ábrázolására tökéletes és helytálló. A könnyebb megértés érdekében csak a legegyszerűbb függvényeket és eljárásokat fogom bemutatni. Saját futásteszt elvégzéséhez javaslom a Online PHP Functions és PHP Benchmark Script benchmark szkriptjeit. (A mért eredmények meglepőek lehetnek.)
A teszteket a phpbench.com eredményei alapján végeztük el. A weboldalon megtalálhatóak a méréshez felhasznált PHP forráskódok is.
MEGJEGYZÉS:
Tartsd észben, hogy sok frissítés is szükséges lehet, hogy a újra és újra igazolást nyerjenek a teszteredmények.
Egyes frissítések után a számok drasztikusan változhatnak.
Feltételezem, ez annak köszönhető, hogy a PHP "garbage collector" tetszőleges időközönként fut le. Emellett a szerveren futó más folyamatok is befolyásolják a futásidőt.
Változó típusának ellenőrzéseisSet() vs. empty() vs. is_array()
Az isSet() és empty() metódustok teljesítménye. 2000 futtatás alapján
isSet() deklarált változó esetén
Teljes futtatási idő: 48 ms
empty() deklarált változó esetén
Teljes futtatási idő: 46 ms
isSet() nem deklarált változó esetén
Teljes futtatási idő: 46 ms
empty() nem deklarált változó esetén
Teljes futtatási idő: 45 ms
isSet() deklarált, tömb típusú változó esetén
Teljes futtatási idő: 46 ms
empty() deklarált, tömb típusú változó esetén
Teljes futtatási idő: 50 ms
isSet() nem deklarált, tömb típusú változó esetén
Teljes futtatási idő: 44 ms
empty() nem deklarált, tömb típusú változó esetén
Teljes futtatási idő: 44 ms
is_array() tömb esetén
Teljes futtatási idő: 173 ms
is_array() string esetén
Teljes futtatási idő: 171 ms
is_array() nem deklarált változó esetén
Teljes futtatási idő: 568 ms
isSet() AND is_array() nem deklarált változó esetén
Teljes futtatási idő: 632 ms
Az isSet() és empty() azonos teljesítménnyel futnak. Mindig ellenőrizd, hogy a változó létezik-e, mielőtt a típusát vizsgálod.
Pl.: if (isSet($foo) AND is_array($foo))
Az & referencia szerinti átadás operátor használata...ún. "alias"
Jó technika az alias operátor használata multidimenzionális tömbök esetén? 1000 futtatás alapján
Pl.: $person = &$aHach["country"]["zip"]["street"]["number"]["name"]
$alias = $aSingleDimArray[$i]
Teljes futtatási idő: 261 ms
$alias = &$aSingleDimArray[$i]
Teljes futtatási idő: 128 ms
$alias = $aMultiDimArray[$i]["aaaaa"]["aaaaaaaaaa"]
Teljes futtatási idő: 265 ms
$alias = &$aMultiDimArray[$i]["aaaaa"]["aaaaaaaaaa"]
Teljes futtatási idő: 451 ms
$alias = veryMultiDimArray[$i]["a"]["aa"]["aaa"]["aaaa"]["aaaaa"]
Teljes futtatási idő: 290 ms
$alias = &$veryMultiDimArray[$i]["a"]["aa"]["aaa"]["aaaa"]["aaaaa"]
Teljes futtatási idő: 741 ms
Egydimenziós tömbök esetén az alias használata kedvező eredménnyel jár, azonban többdimenziós tömbök esetén teljesítményvesztéssel jár.
A =& cím szerinti átadás operátor használata$obj = new SomeClass() vs. $obj =& new SomeClass()
Célszerű a cím szerinti átadás operátor használata új objektum péládnyosításakor? 1000 futtatás alapján
$obj = new SomeClass();
Teljes futtatási idő: 115 ms
$obj =& new SomeClass();
Teljes futtatási idő: 152 ms
Nincs jelentős teljesítménybeli különbség.
Vezérlési szerkezetekswitch/case/default vs. if/elseif/else
Van különbség a switch és if vezérlési szerkezetek teljesítménye között? 1000 futtatás alapján
if and elseif (== használatával)
Teljes futtatási idő: 60 ms
if, elseif and else (== használatával)
Teljes futtatási idő: 60 ms
if and elseif (=== használatával)
Teljes futtatási idő: 51 ms
if, elseif and else (=== használatával)
Teljes futtatási idő: 66 ms
switch / case
Teljes futtatási idő: 62 ms
switch / case / default
Teljes futtatási idő: 62 ms
A switch/case és if/elseif használatában nincs jelentős teljesítmény különbség. Figyeljük meg, hogy az === (érték és típus szerinti azonosság) minimálisan gyorsabb, mint az == (érték szerinti hasonlítás)
Idézőjelek használatadupla (") vs. egyszeres (') idézőjel
Van különbsége a dupla és az egyszeres idézőjel használata között? 1000 futtatás alapján
egyszeres (') idézőjel. Üres string esetén: $tmp[] = '';
Teljes futtatási idő: 82 ms
dupla (") idézőjel. Üres string esetén: $tmp[] = "";
Teljes futtatási idő: 70 ms
egyszeres (') idézőjel. 20 byte-os szöveg esetén : $tmp[] = 'aaaaaaaaaaaaaaaaaaaa';
Teljes futtatási idő: 82 ms
dupla (") idézőjel. 20 byte-os szöveg esetén : $tmp[] = "aaaaaaaaaaaaaaaaaaaa";
Teljes futtatási idő: 95 ms
egyszeres (') idézőjel. 20 byte-os szöveg és 3 $ jel esetén : $tmp[] = 'aa $ aaaa $ aaaa $ a';
Teljes futtatási idő: 67 ms
dupla (") idézőjel. 20 byte-os szöveg és 3 $ jel esetén: $tmp[] = "aa $ aaaa $ aaaa $ a";
Teljes futtatási idő: 78 ms
dupla (") idézőjel. 20 byte-os szöveg és 3 \$ jel esetén: $tmp[] = "aa \$ aaaa \$ aaaa \$ a";
Teljes futtatási idő: 64 ms
Úgy látszik, a jelenlegi PHP verziókban nincs jelentős különbség.
Ciklus számlálókFor vs. While
Van különbség a for és while ciklus számlálók léptetése között?
for($i = 0; $i < 1000000; ++$i);
Teljes futtatási idő: 16388 ms
$i = 0; while($i < 1000000) ++$i;
Teljes futtatási idő: 16129 ms
Az esetek 90%-ában a while ciklus számlálása valóban kissé gyorsabb.
Ciklus számlálókFor-loop test
Megéri a ciklusok számát előre kalkulálni?
Pl.: "for ($i=0; $i<sizeOf($x); $i++)" helyett "for ($i=0; $i<$size; $i++)"
1 cilkus alapján, mely 1000 iterációból áll.
Előkalkulációval - count()
Teljes futtatási idő: 47 ms
Előkalkuláció nélkül - count()
Teljes futtatási idő: 29869 ms
Előkalkulációval - sizeof()
Teljes futtatási idő: 54 ms
Előkalkuláció nélkül - sizeof()
Teljes futtatási idő: 29461 ms
Az eredmény nem meglepő. Ezt a legegyszerűbb implementálni bármely alkalmazásban. Az eredmények önmagukért beszélnek. Ebben a kérdésben a legszélesebb az egyetértés az online PHP közöségek körében.
Módosító ciklusok: foreach() vs. for vs. while(list() = each())
Mi történik, ha a tömb bejárását módosítjuk, minden lépésnél felülírva az adott elem értékét?
A Hash tömbünk 100 elemből áll, melynek kulcsak 24 byte-osak, értékei 10k adatot tartalmaznak.
foreach($aHash as $key=>$val) $aHash[$key] .= "a";
Teljes futtatási idő: 107 ms
while(list($key) = each($aHash)) $aHash[$key] .= "a";
Teljes futtatási idő: 36 ms
$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= "a";
Teljes futtatási idő: 17 ms
Ez a példa jól mutatja, hogy egy foreach ciklus mennyire drasztikus teljesítményromlást képes magával hozni.
String kiíratásecho vs. print
Van különbség a két kiírató függvény teljesítménye között? 1000 Output Bufferelés alapján.
echo ''
Teljes futtatási idő: 23 ms
print ''
Teljes futtatási idő: 23 ms
echo 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa'
Teljes futtatási idő: 67 ms
print 'aaaaaaaaaaaaaaaaaaaaaaaaaaaa'
Teljes futtatási idő: 65 ms
echo 'aaaaaaa'.'aaaaaaa'.'aaaaaaa'.'aaaaaaa'
Teljes futtatási idő: 64 ms
echo 'aaaaaaa','aaaaaaa','aaaaaaa','aaaaaaa'
Teljes futtatási idő: 66 ms
print 'aaaaaaa'.'aaaaaaa'.'aaaaaaa'.'aaaaaaa'
Teljes futtatási idő: 65 ms
$a = 'aaaaaaa';
echo 'aaaaaaa'.$a.'aaaaaaa'.$a
Teljes futtatási idő: 155 ms
$a = 'aaaaaaa';
echo 'aaaaaaa',$a,'aaaaaaa',$a
Teljes futtatási idő: 215 ms
$a = 'aaaaaaa';
print 'aaaaaaa'.$a.'aaaaaaa'.$a
Teljes futtatási idő: 171 ms
$a = 'aaaaaaa';
echo $a.$a.$a.$a
Teljes futtatási idő: 173 ms
$a = 'aaaaaaa';
echo $a,$a,$a,$a
Teljes futtatási idő: 182 ms
$a = 'aaaaaaa';
print $a,$a,$a,$a
Teljes futtatási idő: 172 ms
Valójában az echo és print funkciók teljes mértékben ugyanazt a célt szolgálják és a háttérben ugyanaz a kód fut mindkét esetben. Az egyetlen észrevételünk, hogy amennyiben vesszővel választjuk el a kiírandó tagokat, esetenként minimálisan jobb teljesítményt érhetünk el.
Az =&-referencia-operátor használata $obj = $someClass->f() vs. $obj =& $someClass->f()
Célszerű a =&-referencia-operátor alkalmazása egy adott objektumon történő metódus híváskor? 1000 futtatás alapján
$obj = $someClass->f();
Teljes futtatási idő: 121 ms
$obj =& $someClass->f();
Teljes futtatási idő: 370 ms
Hacsak nincs komoly okod a memóriaproblémák miatt aggódni, nem javasolnám az & használatát ebben az esetben.
Csak olvasást végző ciklusok:foreach() vs. for() vs. while(list() = each())
Melyik a legjobb eszköz a Hash tömbünk bejárására?
A Hash tömbünk 100 elemből áll, melynek kulcsak 24 byte-osak, értékei 10k adatot tartalmaznak.
foreach($aHash as $val);
Teljes futtatási idő: 6 ms
while(list(,$val) = each($aHash));
Teljes futtatási idő: 30 ms
foreach($aHash as $key => $val);
Teljes futtatási idő: 4 ms
while(list($key,$val) = each($aHash));
Teljes futtatási idő: 33 ms
foreach($aHash as $key=>$val) $tmp[] = $aHash[$key];
Teljes futtatási idő: 10 ms
while(list($key) = each($aHash)) $tmp[] = $aHash[$key];
Teljes futtatási idő: 38 ms
Kulcs-érték tömbök kinyerésével: foreach($aHash as $key[]=>$val[]);
Teljes futtatási idő: 14 ms
Kulcs-érték tömbök kinyerésével: array_keys() / array_values()
Teljes futtatási idő: 15 ms
$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) $tmp[] = $aHash[$key[$i]];
Teljes futtatási idő: 17 ms
Minden esetben láthattuk, hogy a foreach ciklus szignifikánsan gyorsabb a for és while ciklusoknál. Megjegyzés: Amennyiben a tömböt legelső elemétől kezdve újra kívánjuk olvasni, erősen ajánlott a reset() funkció alkalmazása, méghozzá bármely esetben.
Leírásaink azon kezdő és haladó programozóknak nyújtanak segítséget, akik már minimális szinten foglalkoztak weboldalkészítéssel. Ha szeretnél jobban elmélyülni a témában, vagy elsajátítani alapokat, még tovább fejlődni, akkor nézz körbe tanfolyam kínálatunkban, ahol a kezdőtől a profi szintig nyújtunk képzéseket a számodra.