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řináším malý PHP kvíz. Každou jeho část představuje krátký kus kódu, který s maličkou změnou najednou začne běžet pomaleji, i když dělá stejné množství práce. Vaším úkolem je poznat co to způsobuje a proč. Odpovědi můžete psát do komentářů.

(Update: Přidal jsem jeden nový kvíz a přidal měření na desktopovém CPU, na kterém rozdíly mnohem víc vynikají).


Na začátek něco jednoduchého:

define('FACTOR', 1);

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

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

Co to způsobuje a jak?


Další dvě otázky jsou už o něco zajímavě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á konstanta INTERVAL hodnotu 1000, poslední smyčka na netbookovém Atomu trvá 3 vteřiny, pokud má hodnotu 2000000, trvá 3.7 vteřin; na desktopovém Haswellu je to pak 0.9 vteřiny pro INTERVAL=1000 a 0.14 vteřiny pro INTERVAL=2000000. Proč je kód až 6x pomalejší, když se indexy generuji z většího intervalu? V jiném jazyku nebo virtuálním stroji by tento rozdíl mohl být ještě větší.


Třetí otázka se nese v podobné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;

Poslední smyčka na netbookovém Atomu proběhne za 1.5 vteřiny, když odstraním řádek $idx = $i, kód běží o víc jak 20% pomaleji (1.8s). Na Haswellu se smyčka vykoná za 0.11 vteřin a pokud odstraním onen řádek, tak za 0.4 vteřiny, tedy skoro čtyřikrát pomaleji. Proč, i když dělám stejné množství práce, ale index se neinkrementuje o jedničku, všechno déle? I tady platí, že v jiném jazyce nebo jiném prostředí by rozdíl mohl být mnohokrát větší.


Dodatečně přidám ještě jednu kvízovou 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 proměnná prefix prázdný string, poslední smyčka trvá 0.24 vteřiny, pokud se $prefix rovná stringu "x", trvá 0.36 vteřiny, ale když místo prefixu použiji postfix (indexace přes $arr[$i.$prefix]), trvá 0.46 vteřiny. Proč se tak děje?

Odpovědi pište do komentářů, za pár dnů tady zveřejním správné odpovědi.

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