BY CHARLES MARSH - HEAD OF COMMUNITY @ TOPTAL (TRANSLATED BY PABLO FABREGAT)
“Python es interpretado o compilado?”
Bytecode vs. código binario
Maquinas virtuales alternativas: Jython, IronPython, y más
Compilación Justo-a-Tiempo: PyPy y el futuro
JIT:
El por qué y el cómo
Artículo original en: Python es asombroso.
Sorprendentemente, esa es una declaración
bastante ambigua. ¿A qué me refiero con ‘Python’?, ¿Me refiero a la interfaz abstracta de
Python?, ¿Me refiero a CPython, la implementación común de Python (y no
confundir con Cython, que son similares en sus nombres)?, ¿O me refiero a algo
completamente distinto? Tal vez me esté refiriendo indirectamente a Jython, o
IronPython, o PyPy. O tal vez me he ido al extremo y estoy hablando de RPython
o RubyPython (los cuales son cosas muy, muy distintas).
Mientras las tecnologías mencionadas
anteriormente son llamadas de formas parecidas y referenciadas de la misma
manera, algunas de ellas sirven para propósitos completamente distintos (o, al
menos, operan de maneras completamente distintas).
A lo largo de mi tiempo trabajando con Python, me topé con toneladas de estas herramientas .*ython.
Pero no hasta hace poco me tomé el tiempo de entender qué es lo que son, cómo
funcionan y por qué son necesarias (a sus maneras).
En este artículo, voy a empezar desde cero y recorreré
varias implementaciones de Python, concluyendo con una introducción detallada a
PyPy, el cual creo es el futuro del lenguaje.
Todo empieza con entender que es lo que ‘Python’ realmente
es.
Si tienes un buen
entendimiento sobre código binario, máquinas virtuales y parecidos, siéntete
libre de saltarte esta parte.
“Python es interpretado o compilado?”
Este es un punto común de confusión para
principiantes en Python.
La primera cosa que
hay que saber es que ‘Python’ es una interfaz. Existe una especificación sobre lo que Python debería hacer y cómo debería comportarse (cómo con cualquier
interfaz). Y hay múltiples implementaciones (como en
cualquier interfaz).
Lo segundo que hay que
saber es que ‘interpretado’ y ‘compilado’ son propiedades de una implementación,
no de una interfaz.
Entonces, la pregunta no está realmente bien
formada.
¿Python es
interpretado o compilado? La
pregunta no está realmente bien formada.
Dicho esto, para la
implementación más común (CPython: escrito en C, usualmente llamado simplemente
‘Python’, y seguramente lo que estás usando si no tienes idea de lo que estoy
hablando), la respuesta es:interpretado,
con algunas partes compiladas.
CPython compila** el código fuente de Python a
*bytecode, y en ese momento interpreta ese bytecode, ejecutándolo sobre la
marcha.
* Nota:
no es una ‘compilación’ en sentido tradicional de la palabra. Normalmente, decimos
que ‘compilar’ es tomar el código de alto nivel y convertirlo en código
binario. Pero es un tipo de ‘compilación’.
Veamos la respuesta un poco más de cerca, ya que
nos permitirá entender algunos de los conceptos que surgirán más adelante en el
artículo.
Bytecode vs. código binario
Es muy importante entender la diferencia entre
bytecode y código binario (o nativo), tal vez mejor ilustrada con ejemplos:
·
C
compila a código binario, que luego es ejecutado directamente en tu procesador.
Cada instrucción le indica a tu CPU que mueva cosas alrededor.
·
Java compila a
bytecode, que luego es ejecutado en la máquina virtual de Java(Java Virtual
Machine, ó JVM), una abstracción de una computadora que ejecuta programas. Cada instrucción es entonces manejada por la JVM, que
interactúa con tu computadora.
En términos breves: código
binario es más rápido, pero bytecode es más portable y seguro.
El código binario se ve distinto, dependiendo de
tu máquina, pero bytecode se ve igual en todas las maquinas. Se podría decir
que el código binario está optimizado para tu configuracion.
Volviendo a CPython, el proceso en el conjunto de
herramientas sucede de la siguiente manera:
1.
CPython
compila tu código Python a bytecode
2.
Ese
bytecode es entonces ejecutado en la Máquina Virtual CPython
Los principiantes
asumen que Python es compilado a raíz de los archivos .pyc. Hay alguna verdad
en esto: el archivo .pyc es bytecode compilado, que es después interpretado.
Entonces si haz ejecutado código Python y ya tienes un archivo .pyc disponible,
el mismo va a ejecutarse más rápido la segunda vez ya que no necesitará
recompilar el bytecode.
Maquinas virtuales alternativas: Jython, IronPython, y más
Cómo mencioné anteriormente, Python tiene varias
implementaciones. De vuelta, como mencioné antes, la más común es CPython. Ésta
es una implementación de Python escrita en C y es considerada la implementación
‘por defecto’.
¿Pero, qué pasa con
las alternativas? Una de las más prominentes esJython, una implementación en Java que utiliza la JVM. Mientras CPython produce bytecode para ser corrido en la
VM de CPython, Jython produce bytecode de Java para correr en la JVM (esto es lo
mismo que es producido cuando se compila un programa en Java).
“¿Por qué usaría
alguna vez una implementación alternativa?”, podrías preguntar. Bueno, para
empezar, esasdiferentes implementaciones juegan muy bien con diferentes
conjuntos de tecnologías.
CPython hace muy
fácil el escribir extensiones C para tu código Python porque al final es
ejecutado por un intérprete de C. Por otro lado, Jython, facilita trabajar con
otros programas en Java: puedes importar cualquier clase de Java sin mayor
esfuerzo, evocando y utilizando tus clases Java dentro tus programas Jython. (Nota
aparte: si no pensaste en esto detalladamente, es una locura. Estamos en un
punto donde puedes mezclar y triturar diferentes lenguajes y compilarlos todos
en una misma esencia. Como fue mencionado por Rostin, los programas que mezclan código Fortran
y C están desde hace un tiempo. Así que, por supuesto que esto no es algo
necesariamente nuevo. Pero sigue siendo genial.)
Cómo ejemplo, esto es código Jython válido:
[Java HotSpot(TM) 64-Bit Server VM (Apple Inc.)] on java1.6.0_51 >>> from java.util import HashSet >>> s = HashSet(5) >>> s.add("Foo") >>> s.add("Bar") >>> s [Foo, Bar]
IronPython es otra implementación popular de Python, escrita
enteramente en C# y apuntando a la tecnología .NET. En particular, corre con lo
que se podría llamar la Máquina Virtual .NET,Common
Language Runtime (CLR)de Microsoft, comparable con la JVM.
Podrías decir que Jython : Java :: IronPython :
C#. Corren en sus respectivas VMs, puedes importar clases C# en tu código
IronPython y clases Java desde tu código Jython, etc.
Es totalmente posible sobrevivir sin tocar alguna
vez una implementación de Python no-CPython. Pero hay ventajas que se obtienen
desde el cambio, muchas de ellas son dependientes de la tecnología que uses.
¿Usas muchos lenguajes basados en la JVM? Jython puede ser para tí. ¿Todo lo
que haces es sobre la tecnología .NET? Tal vez debas probar IronPython (y tal
vez ya lo hayas hecho).
Por cierto: mientras
que esto no sería una razón para usar una implementación diferente, nota que
estas implementaciones sí difieren en comportamiento más allá de como tratan tu
código fuente en Python. Sin embargo, esas diferencias son comúnmente menores,
y se disuelven o emergen con el tiempo mientras estas implementaciones se
encuentran bajo un activo desarrollo. Por ejemplo, IronPython usa
cadenas Unicode por defecto; Sin embargo, CPython, por defecto usa ASCII para versiones 2.x (fallando con un error de
codificaciónUnicodeEncodeError para caracteres no-ASCII), pero sí
soporta cadenas Unicode
por defecto para las versiones 3.x.
Compilación Justo-a-Tiempo: PyPy y el futuro
Por lo tanto, tenemos una implementación de
Python escrita en C, una en Java una en C#. El próximo paso lógico: una
implementación de Python escrita en… Python. (El lector educado encontrará esta
notación levemente engañosa).
Aquí es donde las cosas se ponen confusas.
Primero, discutamos sobre compilación Justo-a-Tiempo (Just-in-Time, ó JIT).
JIT:
El por qué y el cómo
Recordemos que el
código binario es mucho más rápido que bytecode. Bueno,
¿y si pudiéramos compilar algunas partes de nuestro bytecode y luego correrlo
como código nativo? Tendríamos
que pagar algún precio al compilar a bytecode (por ej., tiempo), pero si el
resultado fuese más rápido, eso sería genial! Esa es la motivación de la
compilación JIT, una técnica híbrida que mezcla los beneficios de los
interpretadores y los compiladores. En términos básicos, JIT quiere utilizar
compilación para acelerar un sistema interpretado.
Por ejemplo, un enfoque común tomado por la
compilación JIT:
1.
Identificar
bytecode que es ejecutado frecuentemente.
2.
Compilar
a código binario.
3.
Almacenar
el resultado en memoria caché.
4. Siempre que el mismo bytecode sea
encontrado para ejecutar, en vez de usarlo, ejecutar el código binario
precompilado y cosechar los beneficios (por ej., aumentos de velocidad)
De esto se trata
PyPy: llevar JIT a Python (mira el Apéndice para ver esfuerzos anteriores).
Hay, por supuesto, otros objetivos: PyPy apunta a ser multiplataforma, bajo en
consumo de memoria e independiente del conjunto de tecnologías. Pero JIT
realmente se vende por si solo. Como promedio de un puñado de pruebas de
tiempo, se dice que mejora el rendimiento a un factor de 6.27. Para un mayor análisis, véase este cuadro del PyPy Speed Center:
nice
ResponderEliminar