PHP es uno de los principales lenguajes de desarrollo en Badoo. En nuestros centros de datos, miles de núcleos de procesador están ocupados ejecutando millones de líneas de código PHP. Seguimos de cerca las noticias y buscamos activamente formas de mejorar la productividad, ya que incluso una pequeña optimización en nuestros volúmenes conduce a importantes ahorros de recursos. Una de las principales noticias de rendimiento de PHP es la aparición de JIT en la octava versión del lenguaje. Esto, por supuesto, no podría permanecer sin nuestra atención, y tradujimos el artículo sobre qué es JIT, cómo se implementará en PHP, por qué se decidió hacerlo y qué esperar de él.Si no salió de la cueva o no vino del pasado (en este caso, bienvenido), ya sabe que PHP 8 tendrá JIT: el otro día, votará en silencio y en paz, y la gran mayoría de los participantes votaron a favor de la implementación, por lo que todo está decidido .
En un ataque de alegría, incluso puedes representar varios movimientos locos como en la foto (esto, por cierto, se llama "Detroit JIT":

Ahora, siéntate y lee este artículo que desmiente el mito. Quiero aclarar los malentendidos asociados con lo que es JIT y cómo es útil, y hablar sobre cómo funciona (pero no con demasiados detalles para que no te aburras).
Como no sé quién leerá el artículo, pasaré de preguntas simples a complejas. Si ya conoce la respuesta a la pregunta en el título, puede omitir con seguridad el capítulo correspondiente.
¿Qué es el JIT?
PHP se implementa sobre la base de una máquina virtual (lo llamamos Zend VM). El lenguaje compila el código fuente PHP en instrucciones que la máquina virtual comprende (esto se llama la etapa de compilación). Las instrucciones de la máquina virtual obtenidas en la etapa de compilación se denominan códigos de operación. En la etapa de tiempo de ejecución, la VM Zend ejecuta los códigos de operación, realizando así el trabajo requerido.
Este circuito funciona muy bien. Además, herramientas como APC (antes) y OpCache (hoy) almacenan en caché los resultados de la etapa de compilación, por lo que esta etapa solo se realiza si es necesario.
En resumen, JIT es una estrategia de compilación justo a tiempo (en el momento adecuado), en la que el código se traduce primero en una representación intermedia, que luego se convierte en un código de máquina dependiente de la arquitectura durante la ejecución.
En PHP, esto significa que JIT considerará las instrucciones para la máquina virtual recibidas en la etapa de compilación como una representación intermedia y entregará el código de la máquina que Zend VM ya no ejecutará, sino directamente el procesador.
¿Por qué PHP necesita JIT?
Poco antes de la llegada de PHP 7.0, el enfoque principal del equipo PHP era el rendimiento del lenguaje. La mayoría de los principales cambios en PHP 7.0 se produjeron en el parche PHPNG, que mejoró enormemente la forma en que PHP usa la memoria y el procesador. Desde entonces, cada uno de nosotros tiene que echar un vistazo al rendimiento del lenguaje.
Después del lanzamiento de PHP 7.0, las mejoras de rendimiento continuaron: se optimizó una tabla hash (la estructura de datos principal en PHP), se implementó la especialización de ciertos códigos de operación en Zend VM y la especialización de ciertas secuencias en el compilador, el Optimizador (componente OpCache) se mejoró constantemente y se implementaron muchos otros cambios.
La cruda realidad es que, como resultado de todas estas optimizaciones, nos estamos acercando rápidamente al límite de las oportunidades de mejora de la productividad.
Tenga en cuenta: por "límite de oportunidades de mejora" me refiero al hecho de que las compensaciones que tiene que hacer en aras de nuevas mejoras ya no parecen atractivas. Cuando se trata de optimizar el rendimiento, siempre hablamos de compensaciones. A menudo, por el bien de la productividad, tenemos que sacrificar la simplicidad. A todos les gustaría pensar que el código más simple también es el más rápido, pero en el mundo moderno de la programación en C esto no es así. El más rápido es el código que está preparado para aprovechar la estructura interna de la arquitectura o las estructuras integradas en la plataforma / compilador. La simplicidad por sí sola no garantiza un mejor rendimiento.
Por lo tanto, en esta etapa, la mejor manera de obtener aún más rendimiento de PHP es implementar JIT.
¿JIT acelerará mi sitio?
Lo más probable, insignificantemente.
Es posible que esta no sea la respuesta que esperaba. El hecho es que, en general, las aplicaciones PHP están limitadas por entrada / salida (enlazado de E / S), y JIT funciona mejor con código que está limitado por el procesador (enlazado a la CPU).
¿Qué significa "limitado por E / S y procesador"?
Para describir las características del rendimiento general de algún código o aplicación, utilizamos los términos "limitado por entrada-salida" y "limitado por procesador".
La definición más simple:
- el código limitado por E / S funcionará mucho más rápido si encontramos una manera de mejorar (reducir, optimizar) las operaciones de E / S realizadas;
- el código limitado por el procesador funcionará mucho más rápido si encontramos una manera de mejorar (reducir, optimizar) las instrucciones ejecutadas por el procesador o aumentar mágicamente la velocidad del reloj del procesador.
El código y la aplicación pueden estar limitados por E / S, por procesador o por ambos.
En general, las aplicaciones PHP tienden a estar limitadas por E / S: su principal cuello de botella a menudo son las operaciones de E / S: conexión, lectura y escritura en la base de datos, cachés, archivos, sockets, etc.
¿Cómo se ve el código PHP limitado por procesador?
Quizás algunos programadores PHP son nuevos en el código limitado por el procesador debido a la naturaleza de la mayoría de las aplicaciones PHP: generalmente actúan como un enlace a la base de datos o caché, recogen y producen pequeñas cantidades de respuestas HTML / JSON / XML.
Puede mirar su base de código y encontrar una gran cantidad de código que no tiene nada que ver con E / S, código que llama a funciones que no tienen nada que ver con E / S. Y puede estar confundido de que esto no limita el procesador a su aplicación, aunque su código tiene más líneas que no funcionan con E / S que el trabajo.
El hecho es que PHP es uno de los lenguajes interpretados más rápido. No hay una diferencia notable entre llamar a una función que no usa E / S en Zend VM y en el código de máquina. Por supuesto, hay alguna diferencia, pero tanto el código de máquina como el Zend VM usan la convención de llamada, por lo que no importa
-___()
llama a
-___()
en los
-___()
o en el código de máquina; esto no tendrá un efecto notable sobre el rendimiento de toda la aplicación que realiza la llamada.
Nota: en términos simples, una convención de llamada es una secuencia de instrucciones ejecutadas antes de ingresar a otra función. En ambos casos, la convención de llamada pasa argumentos a la pila.Usted pregunta: "¿Qué pasa con los bucles, las llamadas de cola y más?" PHP es lo suficientemente inteligente, y cuando Optimizer de OpCache está activado, su código se convertirá mágicamente en una versión más eficiente de lo que escribió.
Cabe señalar aquí que JIT no cambiará las convenciones de llamadas de Zend VM. Esto se hace porque PHP debe poder cambiar entre los modos JIT y VM en cualquier momento (por lo tanto, decidieron mantener las convenciones actuales). Como resultado, cualquier llamada que vea en todas partes usando JIT no funcionará mucho más rápido.
Si desea ver cómo se ve el código PHP limitado por el procesador, eche un vistazo aquí:
https://github.com/php/php-src/blob/master/Zend/bench.php . Este es un ejemplo extremo, pero muestra que todo el esplendor de JIT se revela en las matemáticas.
¿Tenía que hacer un compromiso tan extremo para acelerar los cálculos matemáticos en PHP?
No Hicimos esto en aras de ampliar el rango de aplicación del lenguaje (y ampliar significativamente).
No queremos alardear, pero PHP domina la web. Si está involucrado en el desarrollo web y no considera usar PHP en su próximo proyecto, entonces está haciendo algo mal (según un desarrollador de PHP muy sesgado).
A primera vista, puede parecer que la aceleración de los cálculos matemáticos en PHP tiene una aplicación muy limitada. Sin embargo, esto nos abre el camino, por ejemplo, al aprendizaje automático, la representación 3D, la representación 2D (GUI) y el análisis de datos.
¿Por qué no se puede implementar esto en PHP 7.4?
Arriba, llamé a JIT un compromiso extremo, y realmente lo creo: esta es una de las estrategias de compilación más difíciles entre todas las existentes, si no la más difícil. La implementación de JIT es un aumento significativo en la complejidad.
Si le preguntas a Dmitry, el autor de JIT, si hizo que PHP sea complicado, él responderá: "No, odio la complejidad" (esta es una cita).
Esencialmente, "complejo" significa "lo que no entendemos". Y hoy, pocos desarrolladores de lenguaje realmente entienden la implementación existente de JIT.
El trabajo en PHP 7.4 está progresando rápidamente, y la introducción de JIT en esta versión conducirá al hecho de que solo unos pocos pueden depurar, corregir y mejorar el lenguaje. Esto es inaceptable para quienes votaron en contra de JIT en PHP 7.4.
Antes del lanzamiento de PHP 8, muchos de nosotros entenderemos la implementación de JIT. Hay características que queremos implementar y herramientas que queremos reescribir para la octava versión, por lo que primero debemos entender el JIT. Necesitamos este tiempo, y estamos muy agradecidos de que la mayoría votó para dárnoslo.
Complejo no es sinónimo de lo terrible. La complejidad puede ser tan hermosa como una nebulosa de estrella, y esto es solo sobre JIT. En otras palabras, incluso cuando 20 personas en nuestro equipo comienzan a entender JIT no peor que Dmitry, esto no cambiará la complejidad de la naturaleza de JIT.
¿Se ralentizará el desarrollo de PHP?
No hay razón para pensar eso. Tenemos suficiente tiempo, por lo que se puede argumentar que para cuando PHP 8 esté listo, habrá suficientes entre nosotros que dominemos JIT lo suficiente como para trabajar de manera no menos eficiente que hoy cuando se trata de corregir errores y desarrollar PHP.
Cuando intente relacionar esto con la idea de la complejidad original de JIT, recuerde que la mayor parte del tiempo que dedicamos a la introducción de nuevas funciones se dedica a debatirlas. La mayoría de las veces, cuando se trabaja en funciones y se corrigen errores, escribir un código lleva minutos u horas, y las discusiones tardan semanas o meses. En casos excepcionales, el código debe escribirse durante horas o días, pero incluso así las discusiones siempre duran más.
Eso es todo lo que quería decir.
Y como estamos hablando de rendimiento, invito a mi colega Pavel Murzakov al informe el 17 de mayo en la conferencia PHP Rusia. ¡Pasha sabe cómo exprimir la última CPU del segundo código PHP!