funkcionálně.cz

Přední český blog o funkcionálním programování, kde se o funkcionálním programování nepíše
««« »»»

PHP kvíz (aktualizováno)

28. 3. 2014 — k47

Dneska vám při­ná­ším malý PHP kvíz. Každou jeho část před­sta­vuje krátký kus kódu, který s ma­lič­kou změnou na­jed­nou začne běžet po­ma­leji, i když dělá stejné množ­ství práce. Vaším úkolem je poznat co to způ­so­buje a proč. Od­po­vědi můžete psát do ko­men­tářů.

(Update: Přidal jsem jeden nový kvíz a přidal měření na desk­to­po­vém CPU, na kterém roz­díly mnohem víc vy­ni­kají).


Na za­čá­tek něco jed­no­du­chého:

define('FACTOR', 1);

$arr = [];
for ($i = 0; $i < 100000; $i++) {
  $arr[$i * FACTOR] = 1;
}

Pokud je kon­stanta FACTOR rovna jedné, smyčka na Atomu pro­běhne ze 40 milisekund. Pokud se FACTOR rovná 1048576, vykoná se za 84 vteřin.

Co to způ­so­buje a jak?


Další dvě otázky jsou už o něco za­jí­ma­vější.

define('INTERVAL', 1000);

$arr = [];
for ($i = 0; $i < 2000000; $i++) {
  $arr[$i] = ['a' => 1+1];
}

$start = microtime(true);

for ($i = 0; $i < 1000000; $i++) {
  $arr[mt_rand(0, INTERVAL-1)];
}

$time = microtime(true) - $start;

Pokud má kon­stanta IN­TER­VAL hod­notu 1000, po­slední smyčka na net­boo­ko­vém Atomu trvá 3 vte­řiny, pokud má hod­notu 2000000, trvá 3.7 vteřin; na desk­to­po­vém Haswellu je to pak 0.9 vte­řiny pro IN­TER­VAL=1000 a 0.14 vte­řiny pro IN­TER­VAL=2000000. Proč je kód až 6x po­ma­lejší, když se indexy ge­ne­ruji z vět­šího in­ter­valu? V jiném jazyku nebo vir­tu­ál­ním stroji by tento rozdíl mohl být ještě větší.


Třetí otázka se nese v po­dob­ném duchu.

$arr = [];
for ($i = 0; $i < 500000; $i++) {
  $arr[$i] = ["a" => 1+1];
}

$start = microtime(true);

for ($i = 0; $i < 500000; $i++) {
  $idx = mt_rand(0, 500000-1);
  $idx = $i; // tenhle řádek odstraním
  $arr[$idx];
}

$time = microtime(true) - $start;

Po­slední smyčka na net­boo­ko­vém Atomu pro­běhne za 1.5 vte­řiny, když od­stra­ním řádek $idx = $i, kód běží o víc jak 20% po­ma­leji (1.8s). Na Haswellu se smyčka vykoná za 0.11 vteřin a pokud od­stra­ním onen řádek, tak za 0.4 vte­řiny, tedy skoro čty­ři­krát po­ma­leji. Proč, i když dělám stejné množ­ství práce, ale index se ne­in­kre­men­tuje o jed­ničku, všechno déle? I tady platí, že v jiném jazyce nebo jiném pro­středí by rozdíl mohl být mno­ho­krát větší.


Do­da­tečně přidám ještě jednu kví­zo­vou otázku.

$arr = [];
$prefix = ""; // prefix mastavím na "x"
for ($i = 0; $i < 2000000; $i++) {
  $arr[$prefix.$i] = $i;
}

$start = microtime(true);

for ($i = 0; $i < 2000000; $i++) {
  $arr[$prefix.$i];
}

$time = microtime(true) - $start;
echo $time, "\n";

Pokud je pro­měnná prefix prázdný string, po­slední smyčka trvá 0.24 vte­řiny, pokud se $prefix rovná stringu „x“, trvá 0.36 vte­řiny, ale když místo pre­fixu po­u­žiji po­st­fix (in­de­xace přes $arr[$i.$prefix]), trvá 0.46 vte­řiny. Proč se tak děje?

Od­po­vědi pište do ko­men­tářů, za pár dnů tady zve­řej­ním správné od­po­vědi.

@kaja47, kaja47@k47.cz, deadbeef.k47.cz, starší články