Visi, kas daugiau ar mažiau moka programuoti, yra susipažinę su kintamaisiais, sąlygos sakiniais ir ciklais. To dažniausiai mokoma per pirmąsias pamokas. Ciklų naudojimas yra savaime suprantamas ir neišvengiamas, o kokius naudoti kiekvienas renkasi pagal patikimą, naudojimo, užrašymo patogumą, tačiau retas susimąsto dėl ciklų veikimo greičių.
Tikriausiai dažniausiai pasitaikantis ciklas yra FOR – aiškus, paprastas, užrašomas panašiai beveik visose programavimo kalbose: pradinė sąlyga, pabaigos sąlyga ir kitimo žingsnis.
PHP kalboje naudojami ir kiti ciklo sakiniai: FOREACH, WHILE, DO WHILE.
Internete rastas angliškas straipsnis apie javascript ciklų greičio optimizavimą (http://www.webreference.com/programming/optimize/speedup/chap10/3/2.html) užvedė ant minties išsiaiškinti tiesą ir apie PHP.
Labai dažnas internete randamas FOR ciklo užrašymas atrodo taip:
for ($i = 0; $i < count($array); $i++) {..}
Ar kada nors susimąstėte kaip veikia šis ciklas? Jis suskaičiuoja nuo 0 iki tiek kiek elementų yra masyve $array, tačiau kaskart tikrinant sąlygą $i < count($array) yra vykdomas masyvo elementų perskaičiavimas.
Taigi, pasiruošiame pradinius duomenis:
// užpildome masyvą $a 100000 elementų, kurių kiekvienas lygus 5 $a = array_fill(0, 100000, 5);
Visuose cikluose tiesiog suskaičiuosime visų masyvo elementų sumą.
Pirmas bandymas – dažnai sutinkamas ciklo sakinys
$s = 0; for($i=0; $i < count($a);$i++) { $s += $a[$i]; }
Antras bandymas – optimizuotas prieš tai buvęs ciklas
$s = 0; $length = count($a); for($i=0; $i < $length; $i++) { $s += $a[$i]; }
Trečias bandymas – jei panaršysite po gudresnių programuotojų kodą, antrą bandymą galima užrašyti ir taip
$s = 0; for($i=0, $length=count($a); $i < $length; $i++) { $s += $a[$i]; }
Ketvirtas bandymas – anot aukščiau paminėto straipsnio, skaičiavimas atbuline tvarka veikia greičiau nei skaičiavimas aukštyn, pamėginkime
$s = 0; $length = count($a); for ($i = $length-1; $i >= 0; $i--) { $s += $a[$i]; }
Penktas bandymas – dar paoptimizuokime ketvirtą bandymą, nes anot to paties straipsnio --$i veikia greičiau nei $i--
$s = 0; $length = count($a); for ($i = $length; $i > 0;) { $s += $a[--$i]; }
Atkreipkite dėmesį, jog ketvirtame ir penktame bandymuose skaičiavimas atbulinis, todėl norėdami atspausdinti elementus nuo 0 iki $length, gausite įterpti indekso perskaičiavimo operaciją, kuri tikrai pablogins laiką.
Šeštas bandymas – dėl įdomumo, neužmirškime ir pabandykime FOREACH
$s = 0; foreach($a as $key => $value) { $s += $value; }
Septintas bandymas – anot straipsnio, do {} while veikia greičiausiai, bandom, tačiau dėl objektyvumo ir dėl DO sakinio specifikos turime įdėti pradinę IF sąlygą, ir pasitikrinti ar masyvas netuščias
$s = 0; $i = 0; $length = count($a); if ($length > 0) do { $s += $a[$i]; $i++; } while ($i < $length);
Aštuntas bandymas – bandom ar tiesa, jog ++$i veikia greičiau už $i++, optimizuojam septintą bandymą
$s = 0; $i = 0; $length = count($a); if ($length > 0) do { $s += $a[$i]; ++$i; } while ($i < $length);
Devintas bandymas – skaičiavimas žemyn dar greičiau.. bandom
$s = 0; $i = count($a); if ($i > 0) do { $i--; $s += $a[$i]; } while ($i);
Dešimtas bandymas – taigi --$i veikia greičiau nei $i--, tikrinam
$s = 0; $i = count($a); if ($i > 0) do { --$i; $s += $a[$i]; } while ($i);
Atkreipkite dėmesį, jog devintame ir dešimtame bandymuose skaičiavimas atbulinis, todėl norėdami atspausdinti elementus nuo 0 iki count($a), gausite įterpti indekso perskaičiavimo operaciją, kuri tikrai pablogins laiką. Netikite?
Vienuoliktas bandymas - netikintiems
$s = 0; $length = $i = count($a); if ($i>0) do { $s += $a[$length - $i]; --$i; } while ($i);
Rezultatai:
Bandymas | Windows | Ubuntu |
---|---|---|
Pirmas bandymas | 0.040683031082153 | 0.0350840886434 |
Antras bandymas | 0.0119948387146 | 0.011077245076467 |
Trečias bandymas | 0.012179851531982 | 0.0110880533854 |
Ketvirtas bandymas | 0.011506080627441 | 0.0127126375834 |
Penktas bandymas | 0.0093190670013428 | 0.010710716247533 |
Šeštas bandymas | 0.0092620849609375 | 0.011339982350667 |
Septintas bandymas | 0.0098981857299805 | 0.0104285875956 |
Aštuntas bandymas | 0.008842945098877 | 0.009970664978 |
Devintas bandymas | 0.0083010196685791 | 0.0087486902872667 |
Dešimtas bandymas | 0.0075099468231201 | 0.0086693763732667 |
Vienuoliktas bandymas | 0.0087618827819824 | 0.0097419420878 |
Išvados
Dešimtas ciklas veikia greičiausiai, tačiau padarius indekso perskaičiavimą, sulėtėja, bet vis vien rodo geriausius rezultatus. Jei nepatinka atgaliniai skaičiavimai ir papildomi kintamieji, naudokite aštuntą ciklą.
Niekada nenaudokite pirmojo, nes jis veikia ~3 kartus lėčiau nei kiti FOR ar FOREACH ir ~4 kartus lėčiau nei DO {} WHILE