Trucos para acelerar php

Vamos ha realizar un análisis crítico de este vídeo de Eric Higgins, webmaster de Google. En el vídeo nos cuenta alguno de sus trucos para acelerar sus scripts en php:

El primero de los trucos es emplear comillas simples en lugar de comillas dobles. Las comillas dobles hace que la cadena interprete un determinado número de secuencias de escape:

\n linefeed (LF or 0x0A (10) en ASCII)
\r retorno de carro (CR or 0x0D (13) en ASCII)
\t tabulación horizontal (HT or 0x09 (9) in ASCII)
\v tabulación vertical tab (VT or 0x0B (11) in ASCII) (since PHP 5.2.5)
\f form feed (FF or 0x0C (12) in ASCII) (since PHP 5.2.5)
\\ barra invertida
\$ signo de dolar
\” comillas dobles
\[0-7]{1,3} carácter en notación octal
\x[0-9A-Fa-f]{1,2} carácter en notación hexadecimal

Además de, por supuesto, expandir las variables que aparezcan en las cadenas.

En el caso de las comillas simples las únicas secuencias de escape reconocidas son estas dos:

\’ comillas simples
\\ barra invertida

Además de no expandir las variables en la cadena. Por todo ello es lógico pensar que una cadena con comillas simples será más rápida de procesar que una con comillas dobles, veámoslo con un código de ejemplo que después probaremos sin emplear ningún acelerador de php tipo APC o XCache:


echo '==Tests comillas dobles==',"\n";
for($j=0;$j<10;$j++)
{
$t1 = microtime(true);
for($i=0;$i<100000;$i++)
{
$a = "hola mundo";
}
$t2 = microtime(true);
$test1[] = $t2-$t1;
echo $t2-$t1;
echo "\n";
}

echo 'Valor medio: ',array_sum($test1)/($j-1),"\n\n\n";

echo '==Tests comillas simples==',"\n";
for($j=0;$j<10;$j++)
{
$t1 = microtime(true);
for($i=0;$i<100000;$i++)
{
$a = 'hola mundo';
}
$t2 = microtime(true);
$test2[] = $t2-$t1;
echo $t2-$t1;
echo "\n";
}
echo 'Valor medio: ',array_sum($test2)/($j-1),"\n";

Los resultados en mi vieja máquina son los siguientes:

==Tests comillas dobles==
1.2272200584412
1.2168197631836
1.2232639789581
1.2248270511627
1.2338960170746
1.2382409572601
1.5701949596405
1.4171171188354
1.251455783844
1.2365839481354
Valor medio: 1.4266244040595

==Tests comillas simples==
1.2352590560913
1.1931908130646
1.2339069843292
1.2618341445923
1.2174820899963
1.2468011379242
1.2535820007324
1.2457919120789
1.3603079319
1.3120169639587
Valor medio: 1.3955747816298

Parece pues que estamos en lo cierto las comillas simples son más rápidas que las dobles como cabría esperar.

Pero vamos a invertir el orden de las pruebas, empezando ahora por las comillas simples, este es el resultado:

==Tests comillas simples==
1.2222979068756
1.2254979610443
1.2982668876648
1.1845409870148
1.2094640731812
1.1939878463745
1.153324842453
1.2170951366425
1.1506760120392
1.1662788391113
Valor medio: 1.3357144991557

==Tests comillas dobles==
1.2285170555115
1.1904451847076
1.1701879501343
1.184662103653
1.1987600326538
1.1889038085938
1.190358877182
1.1833288669586
1.1585729122162
1.2015302181244
Valor medio: 1.321696334415

¿Como? ¡Las comillas simples con más lentas ahora! en contra de toda nuestra lógica. Después de repetir los tests un buen número de veces estos resultados siguen repitiéndose. Parece que la primera prueba es más lenta que la segunda sin importar que sean comillas dobles o simples. Incluso después de probar repetidas veces el orden de las pruebas no se ha observado ninguna variación.

Vamos ahora con la prueba de la concatenación con print y el echo sin concatenación.

Este es el código para poder ejecutar las pruebas (he empleado output buffering para no volcar por pantalla todos esas decenas de miles de cadenas):


Resultado:

==Print concatenado==
3.2009110450745
3.1793689727783
3.2047038078308
3.1655762195587
3.1424939632416
3.0726661682129
3.2378449440002
3.4216639995575
3.5003128051758
3.1557071208954
Valor medio: 3.5868054495917

==Echo sin concatenación==
3.1254539489746
3.0349171161652
2.9997961521149
2.9809520244598
2.9241809844971
3.1526489257812
2.9299869537354
2.9526100158691
2.9198181629181
2.9321920871735
Valor medio: 3.3280618190765

Invirtiendo las pruebas para comprobar que el orden no afecta al resultado

==Echo sin concatenación==
3.0520401000977
3.184662103653
2.8883378505707
2.8706419467926
3.0163989067078
2.8317699432373
2.856645822525
2.871414899826
2.8769338130951
2.7966349124908
Valor medio: 3.2494978109996

==Print concatenado==
2.8693239688873
2.9165189266205
2.8810060024261
3.0247449874878
2.8426420688629
2.8691411018372
2.8807561397552
2.8754470348358
2.8367080688477
2.8549909591675
Valor medio: 3.2056976954142

La conclusión es que las pruebas no son relevantes y que en estos casos tan sencillos la mejoras en rendimiento no son significativas.

Repitamos las pruebas para cadenas más complejas. Por ejemplo, para la prueba de concatenación con print contra echo y varios argumentos substituimos la línea de echo por:

echo 'h','o','l','a',' ','m','u','n','d','o';

y la de print por:

print 'h'.'o'.'l'.'a'.' '.'m'.'u'.'n'.'d'.'o';

En este caso la mayor velocidad es para el echo no concatenado sin importar el orden. Uno de los tests por ejemplo arrojó estos datos:

Valor medio: 3.6208234363132 (echo)
Valor medio: 3.7140626907349 (print)

Repitiendo varias veces la pruebas y variando el orden el resultado se confirma. Eric Higgins estaba en lo correcto. Aunque con algunos peros, en los casos más simples no se observa mejoras de rendimiento.

Para el caso de las comillas dobles contra las simples debemos modificar las cadenas pero es complejo crear dos cadenas equivalentes que no desvirtúen la prueba. Lo ideal sería emplear sustitución de variables y/o secuencias de escape pero al sólo poder emplearla en una de las dos pruebas no podemos usar formas equivalentes. Lo mejor en este caso es seguir la lógica y emplear las comillas simples en donde podamos. Pero esto da lugar a modificaciones en las cadenas y a operaciones de concatenación extra. ¿Cuál es la mejor solución?. Bien provémoslo:

Siendo
$hola = 'hola';
$mundo = 'mundo';

Intentaremos probar que es mas rápido:

$a = "$hola $mundo";

ó

$a = $hola.' '.$mundo;

Esta prueba si que es más realista y aparece en multitud de ocasiones, en diversas variaciones, en muchos scripts reales.

Los resultados si que son relevantes en este caso, modificando el orden de las pruebas la segunda opción con las comillas simple es siempre más rápida en todas nuestras pruebas sin importar el orden.

Por lo tanto nos ratificamos: la comillas simples son mejores (por lo menos con este nivel de concatenación/sustitución de variables) aunque haya que emplear concatenaciones adicionales a la opción con dobles comillas. Le volvemos a dar la razón a Eric Higgins pero con más peros.

Pruebas realizadas con la siguiente configuración

Versión de php: 5.2.5

Arquitectura/CPU:
processor : 0
vendor_id : AuthenticAMD
cpu family : 15
model : 44
model name : AMD Sempron(tm) Processor 2600+
stepping : 2
cpu MHz : 1596.502
cache size : 128 KB
fdiv_bug : no
hlt_bug : no
f00f_bug : no
coma_bug : no
fpu : yes
fpu_exception : yes
cpuid level : 1
wp : yes
flags : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx mmxext fxsr_opt lm 3dnowext 3dnow up pni lahf_lm ts ttp tm stc
bogomips : 3194.83
clflush size : 64

kernel: Linux 2.6.24.3-custom
Sistema operativo: Ubuntu 9.04 - Jaunty Jackalope (Abril 2009)

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *