¿Qué es PyPy? Python más rápido sin dolor

Python se ha ganado la reputación de ser poderoso, flexible y fácil de trabajar. Estas virtudes han llevado a su uso en una enorme y creciente variedad de aplicaciones, flujos de trabajo y campos. Pero el diseño del lenguaje, su naturaleza interpretada, su dinamismo en tiempo de ejecución, significa que Python siempre ha sido un orden de magnitud más lento que los lenguajes nativos de la máquina como C o C ++.

A lo largo de los años, los desarrolladores han encontrado una variedad de soluciones para las limitaciones de velocidad de Python. Por ejemplo, puede escribir tareas intensivas en rendimiento en C y envolverlas con Python; muchas bibliotecas de aprendizaje automático hacen exactamente esto. O puede usar Cython, un proyecto que le permite rociar código Python con información de tipo de tiempo de ejecución que le permite compilarlo en C.

Pero las soluciones alternativas nunca son ideales. ¿No sería fantástico si pudiéramos tomar un programa Python existente  tal como está y ejecutarlo dramáticamente más rápido? Eso es exactamente lo que PyPy le permite hacer.

Vídeo relacionado: Uso del tiempo de ejecución de PyPy para Python

PyPy frente a CPython

PyPy es un reemplazo directo del intérprete de Python estándar, CPython. Mientras que CPython compila Python en un código de bytes intermedio que luego es interpretado por una máquina virtual, PyPy usa la compilación Just-In-Time (JIT) para traducir el código Python al lenguaje ensamblador nativo de la máquina.

Dependiendo de la tarea que se esté realizando, las ganancias de rendimiento pueden ser dramáticas. En promedio, PyPy acelera Python en aproximadamente 7,6 veces, con algunas tareas aceleradas 50 veces o más. El intérprete de CPython simplemente no realiza los mismos tipos de optimizaciones que PyPy, y probablemente nunca lo hará, ya que ese no es uno de sus objetivos de diseño.

La mejor parte es que se requiere poco o ningún esfuerzo por parte del desarrollador para desbloquear las ganancias que proporciona PyPy. Simplemente cambie CPython por PyPy y, en su mayor parte, ya está. Hay algunas excepciones, que se analizan a continuación, pero el objetivo declarado de PyPy es ejecutar código de Python existente sin modificar y proporcionarle un aumento de velocidad automático.

PyPy actualmente es compatible con Python 2 y Python 3, a través de diferentes encarnaciones del proyecto. En otras palabras, debe descargar diferentes versiones de PyPy según la versión de Python que esté ejecutando. La rama Python 2 de PyPy ha existido por mucho más tiempo, pero la versión Python 3 se ha actualizado últimamente. Actualmente es compatible con Python 3.5 (calidad de producción) y Python 3.6 (calidad beta).

Además de admitir todo el lenguaje central de Python, PyPy funciona con la gran mayoría de las herramientas del ecosistema de Python, como  pip para el empaquetado o  virtualenv para entornos virtuales. La mayoría de los paquetes de Python, incluso aquellos con módulos C, deberían funcionar como están, aunque existen limitaciones que veremos a continuación.

Cómo funciona PyPy

PyPy utiliza técnicas de optimización que se encuentran en otros compiladores just-in-time para lenguajes dinámicos. Analiza la ejecución de programas Python para determinar el tipo de información de los objetos a medida que se crean y usan en los programas, luego usa ese tipo de información como guía para acelerar las cosas. Por ejemplo, si una función de Python funciona con solo uno o dos tipos de objetos diferentes, PyPy genera código de máquina para manejar esos casos específicos.

Las optimizaciones de PyPy se manejan automáticamente en tiempo de ejecución, por lo que generalmente no es necesario modificar su rendimiento. Un usuario avanzado puede experimentar con las opciones de la línea de comandos de PyPy para generar código más rápido para casos especiales, pero esto solo es necesario en raras ocasiones.

PyPy también se aparta de la forma en que CPython maneja algunas funciones internas, pero intenta preservar comportamientos compatibles. Por ejemplo, PyPy maneja la recolección de basura de manera diferente a CPython. No todos los objetos se recopilan inmediatamente una vez que salen del alcance, por lo que un programa de Python que se ejecuta en PyPy puede mostrar una huella de memoria mayor que cuando se ejecuta en CPython. Pero todavía se puede utilizar los controles de recolección de residuos de alto nivel de Python expuestas a través del gcmódulo, como gc.enable(), gc.disable(), y gc.collect().

Si desea información sobre el comportamiento JIT de PyPy en tiempo de ejecución, PyPy incluye un módulo pypyjit, que expone muchos enlaces JIT a su aplicación Python. Si tiene una función o módulo que parece estar funcionando mal con el JIT, le pypyjitpermite obtener estadísticas detalladas al respecto.

Otro módulo __pypy__específico de PyPy expone otras características específicas de PyPy, por lo que puede ser útil para escribir aplicaciones que aprovechen esas características. Debido al dinamismo en tiempo de ejecución de Python, es posible construir aplicaciones de Python que usen estas características cuando PyPy esté presente y las ignore cuando no lo esté.

Limitaciones de PyPy

Por mágico que parezca PyPy, no es mágico. PyPy tiene ciertas limitaciones que reducen u obvian su efectividad para ciertos tipos de programas. Por desgracia, PyPy no es un reemplazo completamente universal para el tiempo de ejecución de CPython estándar.

PyPy funciona mejor con aplicaciones Python puras

PyPy siempre se ha desempeñado mejor con aplicaciones Python "puras", es decir, aplicaciones escritas en Python y nada más. A los paquetes de Python que interactúan con las bibliotecas de C, como NumPy, no les ha ido tan bien debido a la forma en que PyPy emula las interfaces binarias nativas de CPython. 

Los desarrolladores de PyPy han reducido este problema y han hecho que PyPy sea más compatible con la mayoría de los paquetes de Python que dependen de las extensiones C. Numpy, por ejemplo, ahora funciona muy bien con PyPy. Pero si desea la máxima compatibilidad con las extensiones C, use CPython.

PyPy funciona mejor con programas de ejecución más larga

Uno de los efectos secundarios de cómo PyPy optimiza los programas de Python es que los programas de ejecución más larga se benefician más de sus optimizaciones. Cuanto más tiempo se ejecuta el programa, más información de tipo de tiempo de ejecución puede recopilar PyPy y más optimizaciones puede realizar. Los scripts únicos de Python no se beneficiarán de este tipo de cosas. Las aplicaciones que sí se benefician suelen tener bucles que se ejecutan durante largos períodos de tiempo o se ejecutan continuamente en segundo plano, por ejemplo, marcos web.

PyPy no hace una compilación anticipada

PyPy  compila  código Python, pero no es  un compilador  para código Python. Debido a la forma en que PyPy realiza sus optimizaciones y al dinamismo inherente de Python, no hay forma de emitir el código JITted resultante como un binario independiente y reutilizarlo. Cada programa debe compilarse para cada ejecución. Si desea compilar Python en un código más rápido que pueda ejecutarse como una aplicación independiente, use Cython, Numba o el proyecto Nuitka actualmente experimental.