PyPy: ¿cómo puede vencer a CPython?

264

Desde el blog de código abierto de Google :

PyPy es una reimplementación de Python en Python, utilizando técnicas avanzadas para tratar de lograr un mejor rendimiento que CPython. Muchos años de arduo trabajo finalmente han valido la pena. Nuestros resultados de velocidad a menudo superan a CPython, que van desde ser un poco más lentos, a velocidades de hasta 2 veces en el código de aplicación real, a velocidades de hasta 10 veces en puntos de referencia pequeños.

¿Cómo es esto posible? ¿Qué implementación de Python se usó para implementar PyPy? CPython ? ¿Y cuáles son las posibilidades de que PyPyPy o PyPyPyPy superen su puntaje?

(En una nota relacionada ... ¿por qué alguien intentaría algo como esto?)

Agnel Kurian
fuente
43
Nitpick: PyPy es PyPyPy. Piense en el prefijo Py- * como un operador de proyección.
u0b34a0f6ae
Okay. Entonces, ¿PyPy debería preferirse a CPython? ¿Tiene algún inconveniente?
balki
10
PyPy es excelente en la optimización del tiempo de ejecución, pero sus diferentes entrañas lo hacen incompatible con varias extensiones populares de C.
Cees Timmerman
44
Casi todos se están perdiendo la pregunta de cómo una ganancia de velocidad es TEÓRICAMENTE posible. Pero piénselo: Python puede hacer cualquier cosa, como una máquina de Turing. Puede llamar gcc, después de todo. Por lo tanto, también puede escribir algún código de Python que se ejecute en CPython, que interprete algún otro código de Python, lo traduzca a C y ejecute gcc, y luego ejecute el programa compilado. Y podría ser más rápido si el código se llama con la frecuencia suficiente.
osa

Respuestas:

155

Q1. ¿Cómo es esto posible?

La administración manual de memoria (que es lo que hace CPython con su conteo) puede ser más lenta que la administración automática en algunos casos.

Las limitaciones en la implementación del intérprete de CPython impiden ciertas optimizaciones que PyPy puede hacer (por ejemplo, bloqueos de grano fino).

Como mencionó Marcelo, el JIT. Ser capaz de confirmar sobre la marcha el tipo de objeto puede ahorrarle la necesidad de hacer múltiples desreferencias de puntero para llegar finalmente al método al que desea llamar.

Q2 ¿Qué implementación de Python se usó para implementar PyPy?

El intérprete PyPy se implementa en RPython, que es un subconjunto estático de Python (el lenguaje y no el intérprete CPython). - Consulte https://pypy.readthedocs.org/en/latest/architecture.html para más detalles.

Q3. ¿Y cuáles son las posibilidades de que PyPyPy o PyPyPyPy superen su puntaje?

Eso dependería de la implementación de estos hipotéticos intérpretes. Si uno de ellos, por ejemplo, tomó la fuente, hizo algún tipo de análisis y lo convirtió directamente en un código de ensamblaje específico de destino estricto después de ejecutarlo durante un tiempo, imagino que sería bastante más rápido que CPython.

Actualización: recientemente, en un ejemplo cuidadosamente diseñado , PyPy superó a un programa similar de C compilado gcc -O3. Es un caso artificial pero exhibe algunas ideas.

Q4. ¿Por qué alguien intentaría algo como esto?

Desde el sitio oficial. https://pypy.readthedocs.org/en/latest/architecture.html#mission-statement

Nuestro objetivo es proporcionar:

  • Un marco de traducción y soporte común para producir
    implementaciones de lenguajes dinámicos, enfatizando una
    separación clara entre la especificación del lenguaje y los
    aspectos de implementación Llamamos a esto el RPython toolchain_.

  • Una implementación compatible, flexible y rápida del lenguaje Python_ que utiliza la cadena de herramientas anterior para habilitar nuevas funciones avanzadas de alto nivel sin tener que codificar los detalles de bajo nivel.

Al separar las preocupaciones de esta manera, nuestra implementación de Python, y otros lenguajes dinámicos, es capaz de generar automáticamente un compilador Just-in-Time para cualquier lenguaje dinámico. También permite un enfoque de combinación para las decisiones de implementación, incluidas muchas que históricamente han estado fuera del control del usuario, como la plataforma de destino, los modelos de memoria y subprocesos, las estrategias de recolección de basura y las optimizaciones aplicadas, incluso si un JIT en primer lugar.

El compilador C gcc se implementa en C, el compilador Haskell GHC está escrito en Haskell. ¿Tiene alguna razón para que el intérprete / compilador de Python no se escriba en Python?

Noufal Ibrahim
fuente
82
A esta respuesta le falta por completo la explicación principal de cómo PyPy es rápido; Si bien menciona que PyPy no está realmente implementado en Python, pero en RPython, no señala que el código RPython está compilado y optimizado estáticamente para producir el intérprete de PyPy (resulta que también es un código Python válido que puede ejecutarse en la parte superior de CPython mucho más lentamente). Lo que han implementado en "Python normal" es el "compilador" de RPython (el marco de traducción mencionado en la cita de bloque).
Ben
12
Esto está enterrando al lede. La mayor parte del rendimiento proviene de la traducción a C (que hace que el intérprete no sea mucho más lento que CPython), y JIT, que hace que las rutas calientes sean mucho más rápidas.
Tobu
44
"Actualización: recientemente, en un ejemplo cuidadosamente elaborado, PyPy superó a un programa C similar compilado con gcc -O3". Y si lees el primer comentario debajo de esa publicación, verás que el escritor de esa publicación no conoce la optimización del tiempo de enlace. Con la optimización del tiempo de enlace habilitada, el código C se ejecuta más rápido.
Ali
2
Bueno, la publicación del blog fue en 2011 y esta respuesta en 2014. Además, el comentario menciona bibliotecas compartidas. No sé cuánto de esto (respuesta y publicación de blog) es válido. Todas las tecnologías involucradas han cambiado mucho en los últimos años.
Noufal Ibrahim
1
En los dos ejemplos cuidadosamente diseñados de Pypy siendo más rápido que el equivalente C, cada uno es más rápido en el punto de referencia por un conjunto muy específico de razones. El primero porque Pypy es lo suficientemente inteligente como para darse cuenta de que el conteo de bucles cerrados nunca usa ese recuento, por lo que se puede eliminar por completo (pasar JIT) el segundo por una combinación de: porque el Pypy JIT puede "alinearse a través de los límites de la biblioteca", dado el ejemplo de la función "printf" está especializada para literalmente solo poder emitir un número entero, y elimina malloc repetido (sobrecarga de asignación de memoria).
amcgregor
291

"PyPy es una reimplementación de Python en Python" es una forma bastante engañosa de describir PyPy, en mi humilde opinión, aunque es técnicamente cierto.

Hay dos partes principales de PyPy.

  1. El marco de traducción
  2. El interprete

El marco de traducción es un compilador. Compila el código RPython hasta C (u otros objetivos), agregando automáticamente aspectos como la recolección de basura y un compilador JIT. No puede manejar código arbitrario de Python, solo RPython.

RPython es un subconjunto de Python normal; todo el código RPython es código Python, pero no al revés. No existe una definición formal de RPython, porque RPython es básicamente "el subconjunto de Python que puede ser traducido por el marco de traducción de PyPy". Pero para ser traducido, el código RPython tiene que estar estáticamente escrito (los tipos se infieren, no los declaras, pero sigue siendo estrictamente un tipo por variable), y no puedes hacer cosas como declarar / modificar funciones / clases en tiempo de ejecución tampoco.

El intérprete es un intérprete normal de Python escrito en RPython.

Debido a que el código RPython es código Python normal, puede ejecutarlo en cualquier intérprete de Python. Pero ninguno de los reclamos de velocidad de PyPy proviene de ejecutarlo de esa manera; esto es solo para un ciclo de prueba rápido, porque traducir el intérprete lleva mucho tiempo.

Con eso entendido, debería ser inmediatamente obvio que las especulaciones sobre PyPyPy o PyPyPyPy en realidad no tienen ningún sentido. Tienes un intérprete escrito en RPython. Lo traduces a código C que ejecuta Python rápidamente. Allí se detiene el proceso; no hay más RPython para acelerar procesándolo nuevamente.

Entonces, "¿Cómo es posible que PyPy sea más rápido que CPython?" También se vuelve bastante obvio. PyPy tiene una mejor implementación, incluido un compilador JIT (en general, no es tan rápido sin el compilador JIT, creo, lo que significa que PyPy es solo más rápido para programas susceptibles de compilación JIT). CPython nunca fue diseñado para ser una implementación altamente optimizada del lenguaje Python (aunque intentan hacerlo una implementación altamente optimizada , si sigue la diferencia).


La parte realmente innovadora del proyecto PyPy es que no escriben esquemas GC sofisticados o compiladores JIT a mano. Escriben el intérprete de manera relativamente sencilla en RPython, y para todos los RPython tiene un nivel inferior que Python, sigue siendo un lenguaje recolectado de basura orientado a objetos, un nivel mucho más alto que C. Luego, el marco de traducción agrega automáticamente cosas como GC y JIT. Entonces, el marco de traducción es enormeesfuerzo, pero se aplica igualmente bien al intérprete de PyPy python, sin embargo, cambian su implementación, lo que permite mucha más libertad en la experimentación para mejorar el rendimiento (sin preocuparse por introducir errores de GC o actualizar el compilador JIT para hacer frente a los cambios). También significa que cuando implementan un intérprete de Python3, obtendrán automáticamente los mismos beneficios. Y cualquier otro intérprete escrito con el marco PyPy (del cual hay varios en diferentes etapas de pulido). Y todos los intérpretes que usan el marco PyPy admiten automáticamente todas las plataformas compatibles con el marco.

Entonces, el verdadero beneficio del proyecto PyPy es separar (tanto como sea posible) todas las partes de la implementación de un eficiente intérprete independiente de la plataforma para un lenguaje dinámico. Y luego proponga una buena implementación de ellos en un solo lugar, que pueda reutilizarse en muchos intérpretes. Esa no es una victoria inmediata como "mi programa Python se ejecuta más rápido ahora", pero es una gran perspectiva para el futuro.

Y puede ejecutar su programa Python más rápido (tal vez).

Ben
fuente
44
No pude seguir la diferencia :(
polvoazul
37
@polvoazul ¿La diferencia entre una implementación de lenguaje optimizada y una de optimización ? Bueno, cuando digo que CPython es una implementación bien optimizada, quiero decir que los desarrolladores intentan hacer que los algoritmos internos del propio intérprete y las estructuras de datos integradas se ejecuten de manera eficiente. Una implementación optimizada , OTOH, analizaría el código de los usuarios finales y trataría de encontrar formas de transformarlo para ejecutarlo de manera más eficiente.
Ben
23

PyPy se implementa en Python, pero implementa un compilador JIT para generar código nativo sobre la marcha.

La razón para implementar PyPy sobre Python es probablemente que es simplemente un lenguaje muy productivo, especialmente porque el compilador JIT hace que el rendimiento del lenguaje host sea algo irrelevante.

Marcelo Cantos
fuente
¿El JIT genera código Python que se ejecuta al mismo nivel que PyPy, o genera código nativo real que se ejecuta al nivel de cualquier implementación de Python en la que se esté ejecutando PyPy?
Edmund
3
Código nativo real (ver aquí ); Código x86 de 32 bits para ser precisos.
Marcelo Cantos
11

PyPy está escrito en Python restringido. No se ejecuta sobre el intérprete de CPython, que yo sepa. Python restringido es un subconjunto del lenguaje Python. AFAIK, el intérprete de PyPy está compilado en código máquina, por lo que, cuando está instalado, no utiliza un intérprete de Python en tiempo de ejecución.

Su pregunta parece esperar que el intérprete de PyPy se ejecute sobre CPython mientras ejecuta código. Editar: Sí, para usar PyPy, primero debe traducir el código PyPy de Python, ya sea a C y compilar con gcc, a código de byte jvm o al código .Net CLI. Ver Comenzando

revs bobpaul
fuente
8
PyPy se ejecutará sobre CPython pero en este modo no proporciona las ganancias de velocidad que uno podría desear. :-) codespeak.net/pypy/dist/pypy/doc/…
Frank V