¿Qué hay de malo en los artículos populares que dicen que foo es más rápido que bar?

Nota del traductor: también pensé que el tiempo para los artículos es "¿Qué es más rápido: comillas dobles o simples?" Tomó otros 10 años atrás. Pero aquí, un artículo similar ("Qué trucos de rendimiento funcionan realmente") recientemente obtuvo una calificación relativamente alta en Reddit e incluso entró en el resumen de PHP en Habré. En consecuencia, decidí traducir el artículo con un análisis crítico de estas y "pruebas" similares.


Hay muchos artículos (e incluso sitios completos) dedicados al lanzamiento de varias pruebas que comparan el rendimiento de varias construcciones sintácticas y afirman sobre esta base que uno es más rápido que el otro.


Problema principal


Tales pruebas son incorrectas por muchas razones, desde hacer una pregunta hasta errores de implementación. Pero lo más importante: tales pruebas no tienen sentido y al mismo tiempo son dañinas.


  • No tienen sentido porque no tienen ningún valor práctico. Ningún proyecto real se ha acelerado utilizando los métodos proporcionados en dichos artículos. Solo porque no importan las diferencias en la sintaxis para el rendimiento, sino el procesamiento de datos.
  • Son dañinos porque conducen a la aparición de las supersticiones más salvajes y, lo que es peor, alientan a los lectores desprevenidos a escribir códigos incorrectos, pensando que lo "optimizan".

Eso debería ser suficiente para cerrar la pregunta. Pero incluso si acepta las reglas del juego y finge que estas "pruebas" tienen al menos algún sentido, resulta que sus resultados se reducen solo a demostrar la falta de conocimiento del probador y su falta de experiencia.


Individual versus doble


Tome las citas notorias, "simple versus doble". Por supuesto, no hay citas más rápidas. En primer lugar, existe una caché de código de operación , que almacena el resultado de analizar el script PHP en la caché. En este caso, el código PHP se guarda en el formato de código de operación, donde los mismos literales de cadena se almacenan como entidades absolutamente idénticas, independientemente de las comillas que se utilizaron en el script PHP. Lo que significa la ausencia de incluso una diferencia teórica en el rendimiento.


Pero incluso si no usamos caché de código de operación (aunque deberíamos, si nuestra tarea es realmente aumentar el rendimiento), encontraremos que la diferencia en el análisis de código es tan pequeña (varias transiciones condicionales que comparan caracteres de un solo byte, literalmente varias instrucciones del procesador) que será absolutamente indetectable Esto significa que cualquier resultado obtenido solo demostrará problemas en el entorno de prueba. Hay un artículo muy detallado, Desaprobando el mito del rendimiento de las comillas simples del desarrollador principal de PHP Nikita Popov, que analiza este problema en detalle. Sin embargo, un probador enérgico aparece casi cada mes para revelar a la sociedad una "diferencia" imaginaria en el rendimiento.


Inconsistencias lógicas


Algunas pruebas generalmente no tienen sentido, simplemente desde el punto de vista de plantear la pregunta: por ejemplo, la prueba titulada "¿Es el lanzamiento realmente una operación súper costosa?" esta es esencialmente la pregunta "¿Es realmente que procesar un error será más costoso que no procesarlo?". ¿Hablas en serio? Por supuesto, agregar alguna funcionalidad básica al código lo hará "más lento". Pero esto no significa que no sea necesario agregar nueva funcionalidad, bajo un pretexto tan ridículo. Si hablas así, ¡entonces el programa más rápido es uno que no hace nada en absoluto! El programa debería ser útil y funcionar sin errores en primer lugar. Y solo después de lograrlo, y solo si funciona lentamente, debe optimizarse. Pero si la pregunta en sí no tiene sentido, ¿por qué molestarse en probar el rendimiento? Es curioso que el probador no haya podido implementar correctamente incluso esta prueba sin sentido, que se mostrará en la siguiente sección.


O otro ejemplo, una prueba titulada "¿Será $row[id] realmente más lento que $row['id'] ?" esta es esencialmente la pregunta "¿Qué código es más rápido, el que funciona con errores o sin él?" (dado que escribir id sin comillas en este caso es un error del nivel E_NOTICE , y dicha escritura quedará en desuso en futuras versiones de PHP). WTF? ¿Cuál es el punto de medir generalmente el rendimiento del código de error? El error debe solucionarse simplemente porque es un error y no porque hará que el código se ejecute más lentamente. Es curioso que el probador no haya podido implementar correctamente incluso esta prueba sin sentido, que se mostrará en la siguiente sección.


Prueba de calidad


Y nuevamente, incluso una prueba inútilmente consciente debería ser consistente, consistente, es decir, medir valores comparables. Pero, por regla general, tales pruebas se realizan con el talón izquierdo y, como resultado, los resultados obtenidos no tienen sentido y no son relevantes para la tarea.


Por ejemplo, nuestro estúpido probador se comprometió a medir el "uso excesivo del operador try..catch ". Pero en la prueba actual, midió no solo el try catch , sino también el throw , lanzando una excepción en cada iteración del bucle. Pero tal prueba es simplemente incorrecta, porque en la vida real no ocurren errores con cada ejecución de script.


Por supuesto, las pruebas no deben realizarse en versiones beta de PHP y no deben comparar las soluciones convencionales con las experimentales. Y si el probador se compromete a comparar la "velocidad de análisis de json y xml", entonces no debe usar la función experimental en las pruebas.


Algunas pruebas simplemente demuestran un completo malentendido por parte del probador de la tarea establecida por él. Un ejemplo similar de un artículo publicado recientemente ya se mencionó anteriormente: el autor de la prueba trató de averiguar si el código que causó el error ("Uso de constante indefinida") sería más lento que el código sin errores (que usa un literal de cadena sintácticamente correcto), pero falló incluso con esta prueba obviamente sin sentido, que compara el rendimiento de un número entre comillas con el rendimiento de un número escrito sin comillas. Por supuesto, puede escribir números sin comillas en PHP (a diferencia de las cadenas) y, como resultado, el autor probó una funcionalidad completamente diferente y recibió resultados incorrectos.


Hay otros problemas a considerar, como el entorno de prueba. Hay extensiones de PHP como XDebug que pueden tener un gran impacto en los resultados de las pruebas. O el caché de código operativo ya mencionado, que debe incluirse durante las pruebas de rendimiento para que los resultados de la prueba puedan tener al menos algún sentido.


Cómo se realizan las pruebas también es importante. Dado que el proceso PHP muere completamente después de cada solicitud, tiene sentido probar el rendimiento de todo el ciclo de vida, comenzando por crear una conexión a un servidor web y terminando con el cierre de esta conexión. Hay utilidades como Apache benchmark o Siege que te permiten hacer esto.


Mejora de rendimiento real


Todo esto es bueno, pero ¿qué conclusión debería sacar el lector de este artículo? ¿Qué pruebas de rendimiento son inútiles por definición? Por supuesto que no. Pero lo que realmente importa es la razón por la que deberían comenzar. Las pruebas desde cero son una pérdida de tiempo. Siempre debe haber una razón específica para ejecutar pruebas de rendimiento. Y esta razón se llama "perfilado" . Cuando su aplicación comienza a ejecutarse lentamente, necesita hacer un perfil, lo que significa medir la velocidad de varias secciones de código para encontrar la más lenta. Después de encontrar dicho sitio, debemos determinar la causa. Muy a menudo, esto es mucho más grande de lo requerido, la cantidad de datos procesados ​​o una solicitud a una fuente de datos externa. Para el primer caso, la optimización consistirá en reducir la cantidad de datos procesados ​​y en el segundo caso, almacenar en caché los resultados de la consulta.


Por ejemplo, en términos de rendimiento, no importa si usamos un bucle explícitamente prescrito o la función PHP incorporada para procesar matrices (que es esencialmente azúcar sintáctico). Lo realmente importante es la cantidad de datos que transmitimos para su procesamiento. Si es excesivamente grande, debemos recortarlo o mover el procesamiento a otro lugar (a la base de datos). Esto nos dará un gran impulso de rendimiento que será real . Si bien es poco probable que la diferencia entre los métodos para llamar al bucle para el procesamiento de datos sea notable.


Solo después de realizar tales mejoras de rendimiento obligatorias, o si no podemos reducir la cantidad de datos procesados, podemos comenzar las pruebas de rendimiento. Pero, de nuevo, tales pruebas no deben hacerse desde cero. Para comenzar a comparar el rendimiento de un bucle explícito y una función en línea, debemos estar seguros de que el bucle es la causa del problema, no su contenido (spoiler: por supuesto, este es el contenido).


Un ejemplo reciente de mi práctica: en el código había una consulta usando Doctrine Query Builder, que se suponía que debía tomar varios miles de parámetros. La consulta en sí es lo suficientemente rápida, pero Doctrine tarda bastante en digerir varios miles de parámetros. Como resultado, la consulta se reescribió en SQL puro, y los parámetros se transfirieron al método execute () de la biblioteca PDO, que hace frente a tantos parámetros casi al instante.


¿Significa esto que nunca usaré Doctrine Query Builder? Por supuesto que no. Es perfecto para el 99% de las tareas, y continuaré usándolo para todas las consultas. Y solo en casos excepcionales vale la pena usar un método menos conveniente, pero más productivo.


La consulta y los parámetros para esta selección se construyeron en un bucle. Si tuviera una estúpida idea de tratar cómo se llama el ciclo, simplemente perdería tiempo sin ningún resultado positivo. Y esta es la esencia misma de todas las optimizaciones de rendimiento: optimizar solo el código que se ejecuta lentamente en su caso particular. Y no el código que se consideró lento hace mucho tiempo, en una galaxia distante, distante, o el código que se le ocurrió a alguien llamar lento basado en pruebas sin sentido.

Source: https://habr.com/ru/post/es419743/


All Articles