PHP benchmark & dobre prekse (ili ne?)

Slucajno sam naletio na jedan PHP benchmark (
http://www.blueshoes.org/en/developer/php_bench/
) u kojem se daju neke smjernice ka dobrim praksama u PHP-u. Medjutim, testovi nisu dobri. Ajmo redom:

[quote=""]Test:
READ LOOP: foreach() vs. while(list()=each())
What is the best way to loop a hash array?
Given is a Hash array with 100 elements, 24byte key and 10k data per entry
I’ve chosen the large data amount to try out what happens if I reference the data with the &-ref-operator (to avoid copying). But to my surprise the loops are never faster! In tests 5 and 6 are even 10x - 30x slower !! The larger the data entrys are the slower the tests 5 and 6 get! Copying seams always faster then using the &-ref-operator.
Way ???
Let me know at bs_php@users.sourceforge.net

  • 100 % 1: foreach($aHash as $val); Total time: 0[ms]
  • 1196 % 2: while(list(,$val) = each($aHash)); Total time: 1[ms]
  • 2176 % 3: foreach($aHash as $key=>$val); Total time: 2[ms]
  • 3017 % 4: while(list($key,$val)= each($aHash)); Total time: 3[ms]
  • 2300 % 5: foreach($aHash as $key=>$val) $tmp[] = &$aHash[$key]; Total time: 3[ms]
  • 2461 % 6: while(list($key) = each($aHash)) $tmp[]=&$aHash[$key]; Total time: 3[ms]
  • 819 % 7: Get key-/ value-array: foreach($aHash as $key[]=>$val[]); Total time: 1[ms]
  • 864 % 8: Get key-/ value-array: array_keys() / array_values() Total time: 1[ms]
  • 839 % 9: STRANGE: This is the fasetest code when using the the &-ref-operator (to avoid copying)
    $key = array_keys($aHash);
    $size = sizeOf($key);
    for ($i=0; $i<$size; $i++) $tmp[] = &$aHash[$key[$i]]; Total time: 1[ms]
    Conclusion:
    It must have something to do with PHP4 variable ref-count So you can safely use foreach and only use the &-ref-operator when realy needed OR (according to the link above) when passing objects to functions. (Thanx to Wayne for his help)[/quote]

Prva greska je u pretpostavci " if I reference the data with the &-ref-operator (to avoid copying)". Naime, ako se ne koristi operator “&” u foreach petlji (foreach($aHash as $key => $value)), nista se ne kopira - ukoliko se ne modificira (a u ovom testu se ne modificira)! Dok, s druge strane, kad se koristi operator “&” u foreach petlji (foreach($aHash as $key => &$value)) dolazi do kopiranja - ali ne vrijednosti, nego se stvara novi alias varijable (“kopija imena”) u tablici simbola.

Sljedeca pogreska (bar koliko mi se cini) je usporedjivanje:

sa

Ove dvije naredbe nisu jednake. Naime, u drugoj postoji jedna “mikro”-naredba vise - pridjeljivanje jedne varijable naspram pridjeljivanje dvijema varijablama.

[quote=""]Test:
MODIFY LOOP: foreach() vs. while(list()=each())
While the above test only reads and copies the data the question arised what would happen if I modify each value of the hash above.
Again I an unexpected result. Even if I reduce the data size to 100 byte p. e. it ends up that Nr.3 is 1.5 - 2x faster.

  • 272 % 1: foreach($aHash as $key=>$val) $aHash[$key] .= “a”; Total time: 3[ms]
  • 128 % 2: while(list($key) = each($aHash)) $aHash[$key] .= “a”; Total time: 1[ms]
  • 100 % 3: STRANGE: This is the fasetest code :
    $key = array_keys($aHash);
    $size = sizeOf($key);
    for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= “a”; Total time: 1[ms]
    Conclusion:
    Use foreach unless the hash is lage AND has lage data elements. In that case use variation Nr.3 .[/quote]

Znajuci gornju recenicu kako se vrijednost polja kopira tek kad se modificira, ovaj rezultat uopce nije cudan (dapace, sasvim je logican). :slight_smile:

Osim toga, while petlja nije dobro izsimulirana. Prije while petlje bi trebala doci “reset” funkcija koja vraca unutrasnji pointer polja na pocetak (ne mora se nuzno, ako je rijec o samo jednom ponavljanju testa, medjutim u stvarnim situacijama se uvijek stavi “@reset” ispred petlje kako bi bili sigurni da je unutrasnji pointer polja na prvom mjestu) jer se inace ne dobije dobar rezultat ako se prije pomakao unutrasnji pointer polja.

I sta je najgore u svemu - najbrza petlja je izostavljena iz testa. :krele:

Daleko najbrza petlja (po mojim testovima) je:

Sta je sasvim logicno.

Rezime:

foreach petlja je najbrza (iako, while je mozda tek nesto sporija). Koji oblik foreach petlje koristiti (sa ili bez reference) ovisi o tome zelimo li modificirati vrijednost polja ili ne. Ako se vrijednost ne modificira najbolje je koristiti:

ili ukoliko je kljuc od interesa u petlji:

zato jer se u tom slucaju vrijednost polja nece kopirati (samo ce se procitati, dok kod verzije foreach petlje sa & operatorom, kopirat ce se ime varijable u tablici simbola koja sa drzava popis svih varijabli).
Napomena: ukoliko se cita vrijednost polja, bolje je koristiti $value naspram $aHash[$key].

Ukoliko se polje modificira najbolje je koristiti verziju foreach petlje sa “&” operatorom:

a modifikaciju raditi preko aliasa vrijednosti polja - $value.

Sve u svemu - PHP je optimiziran jezik i ne treba previse lutati izmisljajuci svoje funkcije i algoritme, nego treba koristiti ono sta je jezik ponudio jer je to u 99% slucajeva najbolje. Dobro poznavanje jezika je kljucno! :wink:

NEXT! :smiley:

[quote=""]Test:
For-loop test
Is it worth the effort to calculate the length of the loop in advance?
E.g. “for ($i=0; $i<$size; $i++)” instead of “for ($i=0; $i<sizeOf($x); $i++)”

  • 100 % 1: With pre calc Total time: 1[ms]
  • 789 % 2: Without pre calc Total time: 8[ms]
    Conclusion:
    The test above speeks for it self. Always calculate the length of the loop in advance!
    [/quote]

Test bez pravog razumjevanja. U drugoj petlji se “count” (sizeOf) racuna svaki put u petlji i stoga ima vise operacija, pa je sasvim logicno da je npr. 100 prebrojavanja koliko clanova ima polje je sporije od samo jednog prebrojavanja. :slight_smile:

[quote=""]Test:
Using the &-ref-operator as so called "alias"
Is a good idea to use the &-ref-operator to substitute (or alias) a complex mutidim-array? . Call 1’000x
E.g. $person = &$aHach[“country”][“zip”][“streat”][“number”][“name”]

  • 103 % 1: NO Aliasing. Using: $aSingleDimArray[$i] Total time: 1[ms]
  • 100 % 2: Aliasing. Using: $alias = &$aSingleDimArray[$i] Total time: 1[ms]
  • 186 % 3: NO Aliasing. Using: $aMultiDimArray[$i][“aaaaa”][“aaaaaaaaaa”] Total time: 1[ms]
  • 127 % 4: Aliasing. Using: $alias = &$aMultiDimArray[$i][“aaaaa”][“aaaaaaaaaa”] Total time: 1[ms]
  • 284 % 5: NO Aliasing. Using: veryMultiDimArray[$i][“a”][“aa”][“aaa”][“aaaa”][“aaaaa”] Total time: 2[ms]
  • 163 % 6: Aliasing. Using: $alias = &$veryMultiDimArray[$i][“a”][“aa”][“aaa”][“aaaa”][“aaaaa”] Total time: 1[ms]
    Conclusion:
    It seams to be ok to use aliases. It also makes the code more readabel. But I was expecting to get a lager performance gain; especially with very multdimetional arrays.[/quote]

Nisam radio svoje testove, ali mislim da je test OK, iako se s ovim ne treba opterecivati jer rijetko kad (ako ikad) cemo biti u situaciji da imamo polje sa velikim brojem dimenzija (a s malim brojem razlika je nebitna, ako ikakva).

[quote=""]Test:
$obj = new SomeClass() vs. $obj =& new SomeClass() using the =&-ref-operator
Is a good idea to use the =&-ref-operator when creating a new object? Call 1’000x

  • 100 % 1: $obj = new SomeClass() Total time: 1[ms]
  • 100 % 2: $obj =& new SomeClass() Total time: 1[ms]
  • 944 % 3: $obj =& $someClass->f(); Total time: 7[ms]
  • 133 % 4: $obj = $someClass->f(); Total time: 1[ms]
    Conclusion:
    There seams to be no difference in performance.[/quote]

Nema razlike u performansama - ali ima u funkcionalnosti (btw, broj 3 i 4 nemaju smisla u ovom testu)!
O tome sam vec nesto pisao:

http://webmajstori.net/forum/showpost.php?p=191110&postcount=43

http://webmajstori.net/forum/showpost.php?p=191112&postcount=45

[quote=""]Test:
double (") vs. single (’) quotes
Is a there a difference in using double (") and single (’) quotes for strings. Call 1’000x

  • 103 % 1: single (’) quotes. Just an empty string: $tmp[] = ‘’; Total time: 0[ms]
  • 105 % 2: double (") quotes. Just an empty string: $tmp[] = “”; Total time: 0[ms]
  • 100 % 3: single (’) quotes. 20 bytes Text : $tmp[] = ‘aaaaaaaaaaaaaaaaaaaa’; Total time: 0[ms]
  • 109 % 4: double (") quotes. 20 bytes Text : $tmp[] = “aaaaaaaaaaaaaaaaaaaa”; Total time: 0[ms]
  • 100 % 5: single (’) quotes. 20 bytes Text and 3x a $ : $tmp[] = ‘aa $ aaaa $ aaaa $ a’; Total time: 0[ms]
  • 491 % 6: double (") quotes. 20 bytes Text and 3x a $ : $tmp[] = “aa $ aaaa $ aaaa $ a”; Total time: 1[ms]
  • 101 % 7: double (") quotes. 20 bytes Text and 3x a $ : $tmp[] = “aa $ aaaa $ aaaa $ a”; Total time: 0[ms]
    Conclusion:
    Single and double quoted strings behave almost the same with one exception: Don’t use the a lonely ($) in double quoted string unless you want to reference a PHP-var; or use ($).
    [/quote]

Testovi su pogresni, posto su jednostruki navodnici sigurno barem nesto brzi, posto se dvostruki navodnici parsiraju (traze se varijable koje se zamjenjuju sa njihovom vrijednosti).

[quote=""]Test:
isSet() vs. empty() vs. is_array()
What is the performance of isSet() and empty(). Call 2’000x

  • 119 % 1: isSet() with var that was set Total time: 0[ms]
  • 121 % 2: empty() with var that was set Total time: 0[ms]
  • 104 % 3: isSet() with var that was not set Total time: 0[ms]
  • 108 % 4: empty() with var that was not set Total time: 0[ms]
  • 103 % 5: isSet() with array-var that was set Total time: 0[ms]
  • 105 % 6: empty() with array-var that was set Total time: 0[ms]
  • 113 % 7: isSet() with array-var that was not set Total time: 0[ms]
  • 100 % 8: empty() with array-var that was not set Total time: 0[ms]
  • 201 % 9: is_array() of an array Total time: 1[ms]
  • 234 % 10: is_array() of a string Total time: 1[ms]
  • 3490 % 11: is_array() of a non set value Total time: 9[ms]
  • 109 % 12: isSet() AND is_array() of a non set value Total time: 0[ms]
    Conclusion:
    isSet() and empty() are identical. Interesting that a is_array() on a unset val is 3x slower. So alway check if val is set at all befor using type-checking. E.g. if (isSet($foo) AND is_array($foo))[/quote]

Ovi testovi nisu dobri posto testiraju 3 funkcije od kojih svaka provjerava razlicitu stvar (ko mi ne vjeruje neka pogleda dokumentaciju :smiley: ).

I na kraju:

[quote=""]Test:
switch/case vs. if/elseif
Is a there a difference between switch and if elseif. Call 1’000x

  • 141 % 1: if and elseif (using ==) Total time: 0[ms]
  • 100 % 2: if and elseif (using ===) Total time: 0[ms]
  • 146 % 3: case Total time: 0[ms]
    Conclusion:
    Using a switch/case or if/elseif is almost the same. Note that the test is unsing === and is slitly faster then using ==.[/quote]

Opet pogreska u razumijevanju jezika. “===” je striktna usporedba (usporedjuje se i tip varijable i njena vrijednost) dok je “==” ne-striktna :zub: usporedba (usporedjuje se samo vrijednost varijable). “===” je brza od “==”, tako da su rezultati logicni. Switch i if su priblizno jednaki sta se tice performansi sta je meni sasvim logicno.


Sve u svemu, ovo je primjer kako NE RADITI testiranja. Treba se prije svega dobro razumjeti jezik, a ovakve optimizacije (iako generalno gledano nisu toliko ni bitne), odnosno - dobre prakse - se namecu same po sebi.

foreach petlja je vjerovatno najbrža zato jer ne provjera nikakav uvijet.

Operator & nikad ne koristim iako mi je nedavno zatrebao ali sam kreirao još jedan array i njemu dodjelio potrebne vrijednosti koje je trebalo mjenjati u prvom arrayu.
Što vjerovatno nije bilo najbolje rješenje.
Primjetio sam u nekim frameworcima ga obilatio koriste a negdje ga ne koriste uopće.
Neznam koja bi bila najbolja praksa. Vjervatno prema potrebi.

Ovo mi doduše nije logično, “===” je brži od “==”.
Ako prvi treba utvrditi tip i vrijednost dok drugi treba samo vrijednost. Još se radi o jeziku koji nije striktni.

U strpos kad se koristi while za pretraživanje ne može se raditi provjera sa == jer ako strpos vrati 0 onda imamo jednakost za false. Davno sam to obilato koristio to actionscriptu i on kao striktni jezik nema taj problem jer ako nešto vraća INT onda vraća INT. Iako se i 0 može koristiti kao false ali vjerovatno ne kod uspoređivanja.

Baš sam isprobao i nije istina. Evo moram priznati da lažem samo neznam kako onda nisam naišao na taj problem u AS.
Davno je to bilo.

E da treba i u AS koristiti ===.

nije da nemam pametnijeg posla no kad sam već u prolazu:

ma to su zanemarive nijanse…

Kakav uvjet?

[quote=“gorrc”]
Neznam koja bi bila najbolja praksa. Vjervatno prema potrebi.[/quote]

Pa da, kad ima smisla, koristis ga, kad nema ne koristis. Performanse su tu mozda sporedne, nekad je mnogo lakse baratati sa & …

[quote=“gorrc”]
Ovo mi doduše nije logično, “===” je brži od “==”.
Ako prvi treba utvrditi tip i vrijednost dok drugi treba samo vrijednost. Još se radi o jeziku koji nije striktni.[/quote]

Uzmi neki konkretan primjer, npr.

$str = ‘Test’;
$arr = array(‘abc’);

$str == $arr pretvara podatke da bi ih mogao usporediti, radi usporedbu i na temelju usporedbe vraca true ili false

$str === $arr gleda tip podatka, ako nisu isti vraca false, inace radi usporedbu

Dakle, razlika u performansi se dobije u pretvorbi podataka.

U 90% (ako ne i vise) slucajeva jesu. Medjutim, to ne znaci da se tih stvari ne bi trebalo pridrzavati. Ukoliko se pri pisanju koda (bilo kakvog, ne samo PHP koda) pridrzava “dobrih praksi”, smanjuje se vjerojatnost kasnijih optimizacija, gresaka, itd.

naravno, ali isto tako treba imati i dobar balans između brzine izvršavanja koda, čitljivosti koda i brzine programiranja, nije nužno najbrži kod uvijek najbolji…

[quote=“ivan.skugor”]Kakav uvjet?
.[/quote]
Sve ostale petlje su ovisne o nekom uvijetu.
Ako je neka vrijednost zadovoljena onda izvrši nešto ili prvo izvrši pa provjeri je vrijednost ok dok foreach nikad ne provjera neki uvijet.

[quote=“ivan.skugor”]
Uzmi neki konkretan primjer, npr.

$str = ‘Test’;
$arr = array(‘abc’);

$str == $arr pretvara podatke da bi ih mogao usporediti, radi usporedbu i na temelju usporedbe vraca true ili false

$str === $arr gleda tip podatka, ako nisu isti vraca false, inace radi usporedbu

Dakle, razlika u performansi se dobije u pretvorbi podataka.[/quote]
Da, ja sam gledao da “==” samo radi usporedbu.
No što kad bi imali slučaj da usporedba tipa podatka vrati true, onda bi “===” trebalo biti sporije jer provjerava i tip podatka te radi usporedbu.

[quote=“gorrc”]
No što kad bi imali slučaj da usporedba tipa podatka vrati true, onda bi “===” trebalo biti sporije jer provjerava i tip podatka te radi usporedbu.[/quote]
a možda bi i trebalo biti brže jer ne radi nikakav casting već samo provjerava dal su svi bitovi jednaki?? to bi trebalo ispitat

Da, === ne radi casting i zbog toga bi trebao biti brži.

[quote=“gorrc”]Sve ostale petlje su ovisne o nekom uvijetu.
Ako je neka vrijednost zadovoljena onda izvrši nešto ili prvo izvrši pa provjeri je vrijednost ok dok foreach nikad ne provjera neki uvijet.
[/quote]

Ima smisla to sta pricas. Samo ne znam dal je u potpunosti istina. Vjerovatno se interno provjerava da li ima jos clanova niza (ili nesto u tom smislu).

mislim da je foreach najsporiji, obična for petlja bi bila brža, no ko zna što se sve događa u pozadini, trebalo bi uzeti source code php-a pa ići gledat…

da mora postojati neki unutarnji uvjet ali je vjerovatno brži.

da ne postoji neki uvjet prekida onda bi foreach bila beskonačna petlja :smiley: malo razuma ljudi :slight_smile:

Kako se ono kaze … misliti je drek znati. :smiley:

Mozda … da ne moras prije petlje pobrojati elemente.

[quote=“ivan.skugor”]Kako se ono kaze … misliti je drek znati. :smiley:

Mozda … da ne moras prije petlje pobrojati elemente.[/quote]

ma ne vidio sam neke benchmarke već prije(još kad sam se koliko toliko bavio php-om) i mislim da je razlika bila možda i 5-6 puta veća nego na for petlji, a i ja sam došao iz svijeta c+±a :smiley: koji foreach :smiley:


Copyright © 2020 WM Forum - AboutContact - Sponsored by: Mydataknox & Webmaster.Ninja