29 de mai. de 2013

PHP: obtenha a melhor performance ao percorrer arrays

Os que me conhecem sabem que não sou grande fã do PHP, muito pelo contrário, é uma das linguagens mais deselegantes que conheço, contudo programo em PHP sempre que necessário e não tenho medo de sujar as mãos :)

Para ninguém dizer que não contribuo com a comunidade PHP trouxe este post, que partiu de um tópico na lista do curso de Análise e Desenvolvimento de Sistemas no IFRS, que fala a respeito de como iterar arrays no PHP obtendo a melhor performance.

Quando digo performance, não pense que seus programas PHP irão dobrar de velocidade, na verdade são micro-otimizações, ou seja, reduzem o tempo de resposta em milisegundos até décimos de milisegundos, mas que na quantidade de acessos simultâneos, por exemplo um Web Site com muitos page views, pode trazer ganhos significativos.

Indo ao ponto, os arrays no PHP, ou arrays associativos, não são como os arrays primitivos de outras linguagens, eles são na verdade um map, ou dicionário, e são armazenados como hash tables através de bindings em C. Dito isso, há características interessantes que trazem alterações na performance dependendo da maneira como é feito, por exemplo, este modo de iterar um array tem pouca performance:

$elementos = array();
 
for ($i = 0; $i < 1000000; $i++) $elementos[$i] = rand();    

$inicio = microtime(true);

for ($i = 0; $i < count($elementos); $i++) {
    $elementos[$i];
}    

$fim = microtime(true);

echo ($fim - $inicio);
Esta implementação executa em 0.366 segundos no meu humilde notebook que é muito tempo se comparada a este implementação a seguir que executa em 0.106 segundos:
$elementos = array();
 
for ($i = 0; $i < 1000000; $i++) $elementos[$i] = rand();    

$inicio = microtime(true);

for ($i = 0, $count = count($elementos); $i < $count; $i++) {
    $elementos[$i];
}    

$fim = microtime(true);

echo ($fim - $inicio);
A grande diferença está na função count, a qual é custosa em tempo, logo é melhor fazê-la uma única vez, na inicialização do for, em vez de introduzi-la na condição de saída. Mas não acabou ainda, esta implementação é ainda melhor (0.085 segundos):
$elementos = array();
 
for ($i = 0; $i < 1000000; $i++) $elementos[$i] = rand();    

$inicio = microtime(true);

foreach ($elementos as $e) {
    $e;
}   

$fim = microtime(true);

echo ($fim - $inicio);

O foreach é otimizado para atravessar o array através da estrutura de dados utilizada, uma lista ligada (linked list).

Existem outras micro-otimizações que trarei num próximo post.

Um comentário:

welonikaabadie disse...

CASINO DE LUGGINS LAKEPORT, KAYLAN, VA | JTM Hub
CASINO DE 아산 출장샵 LUGGINS LAKEPORT, KAYLAN, VA - JULY 25, 김해 출장마사지 2021. JTM has a long 경기도 출장마사지 list 통영 출장안마 of casinos in La Mesa and has a number 양주 출장마사지 of different types of casino games.