Mirin webspace

Nejbohatší život má ten, kdo žije s minimem nároků

2. 8. 2011 - Komentáře (8) PHP

Ternární operátor může být velká brzda

Ternární operátor osobně využívám docela často, proto mě nedávno překvapil příspěvek na blogu Fabiena Potenciera, který se zmiňuje o tom, že ternární operátor může být za určitých okolností až 1000x i více pomalejší než použití konstruktu if.

Problém je v tom, že chování ternárního operátoru je interně v PHP representováno tak, že vždy vrací kopii operandu a nepoužívá tedy mechanizmus copy on write, který je běžný např. pro obyčejný operátor přiřazení.

//huge array
for ($i = 0; $i < 100000; $i++) {
    $content['test'][$i] = $i;
}
 
//very slow
$test = isset($content['test']) ? $content['test'] : '';
//fast
if (isset($content['test']) {
 $test = $content['test'];
} else {
 $test = '';
}
 
//huge string
$content = file_get_contents('http://www.w3.org/TR/2011/WD-html-markup-20110525/spec.html');
 
//very slow
$test = $content !== false ? $content : '';
//fast
if ($content !== false) {
 $test = $content;
} else {
 $test = '';
}

Určitě bych se v důsledku tohoto nevzdával ternárního operátoru, který využívám zejména proto, protože je to výraz jehož výsledkem je hodnota. Většina porovnávání ternárního operátoru bývá na malinkých datech, ale určitě je dobré o tomhle nepěkném chování vědět. V internals se podle komentářů na originálním článku už o tom ví. Zatím to nevypadá, že by to bylo opraveno, tak snad časem na to budeme moci zapomenout.

Pozn: Na stejný problém upozornil již před pár lety D. Grudl. Jen doplním, že já se k aktuálnímu chování stavím jednoznačně negativně i vzhledem k tomu, že se to přeneslo z verze 4 do verze 5.


Komentáře (8)

  1. paranoiq - 2. 8. 2011 16:04

    ale to je přeci pět let známá věc :]
    http://latrine.dgx.cz/php-puvab-optimalizace-rychlosti

    ale díky za připomenutí

  2. koubel - 2. 8. 2011 20:42

    No ano, sranda je, že to asi lidi moc nepálí, jinak si nedovedu vysvětlit, že to tak dlouhou dobu nikdo neopravil.

  3. Sniper - 2. 8. 2011 21:26

    [2] Podle me je to tim, ze 99% ternarnich operatoru se pouziva s funkcema is_null(), empty(), isset() apod, ktere vraci bool, takze ten ternarni operator kopiruje nanejvejs ten bool a ten je minimalistickej.

  4. SendiMyrkr - 2. 8. 2011 22:19

    [3] Já myslim že problém neni v části před otazníkem, ale v tom, za nim, schválně si přečti ten článek od Davida uvedený výše...

    Pochopil jsem to tak, že se vyhodnotí výraz a neprovede se klasický přiřazení stylem reference countingu, ale rovnou přiřazení(kopírování) hodnoty čož v případe velkého textu chvíli zabere...

    Osobně v tom ale problém nevidim, protože ve chvíli kdy použiju ternární operátor tak stejně v případě kdy s tou proměnnou mám vplánu dál pracovat, takže ke kopírování hodnoty stejně dojde, byť později...

  5. koubel - 2. 8. 2011 23:07

    [3] ne, výraz před otazníkem v ternárním operátoru s tímto chováním opravdu nemá nic společného

    [4] neřekl bych, zrovna u velkých řetězců to může být problém, je běžné, že nějaký velikánský řetězec načtu a pak ho jen zpracovávám ale už ho neměním a pokud použiji ternární operátor výše popsaným způsobem jsem v pytli. U polí to asi bude menší problém, ty se modifikují spíše.

  6. v6ak - 17. 8. 2011 10:03

    Ať jsem se snažil, jak jsem se snažil, nepovedlo se mi udělat nějaký zásadní výkonnostní rozdíl. Co dělám špatně?

    https://gist.github.com/1151069

  7. koubel - 18. 8. 2011 16:37

    [6] no to je mi teda bashophpmaso, pustil jsem si to a nechal si vypsat ten kód, co je vykonáván a přijde mi, že testujete ternární operátor pokaždé zhruba takto :

    $content !== false ? 1 : 2
    
    jestli je to opravdu tak, tak místo obrovského $content se kopíruje buď "1" nebo "2", což je opravdu rychlé jako blesk.

  8. v6ak - 22. 8. 2011 19:50

    [7] Aha, už jsem ty benchmarky opravil, takže už dostávám ony očekávané výsledky.

    Jinak takovéto "bashophpmaso" obvykle nedělám, ale pro benchmark mi přišlo celkem praktické.

Komentáře jsou uzavřeny.