Está en la página 1de 5

PORTADA Acelerando Python

Herramientas para hacer ms rpidos los programas escritos en Python

MS RPIDO

James Barber - 123rf.com

Python es un lenguaje maravilloso, a pesar de que no destaque por la velocidad. Veremos cmo inyectar un poco de adrenalina a nuestro cdigo Python. POR ANKUR KUMAR SHARMA
ython es uno de los mejores lenguajes de programacin jams creados. Es increblemente sencillo de usar y cuenta con una enorme librera. Proporciona adems al programador una productividad y una flexibilidad excelentes. Por desgracia, en cuanto a rendimiento ha perdido la batalla. Python es un lenguaje basado en bytecode, compilado y dinmico, que se ejecuta a travs de su mquina virtual, motivo por el cual los programas escritos en Python resultan ms lentos que aquellos escritos en lenguajes de compilacin nativa, como C o C++. Otro problema de Python es su falta de soporte para los ya estndar procesadores multincleo. Estos factores, que merman la velocidad de Python, resultan frustrantes para los desarrolladores, los cuales a menudo se ven obligados a escribir trozos de cdigo en C o C++

para equilibrar el rendimiento de Python. Por suerte, la comunidad de FLOSS proporciona ciertas herramientas con las que podemos acelerar nuestros programas escritos en Python.

Por Qu Es Python Lento?


La respuesta a la pregunta de por qu los programas escritos en Python son ms lentos que los creados mediante lenguajes como C o C++ reside en las capas y transformaciones llevadas a cabo por Python antes de la ejecucin de dichos programas. Cuando compilamos y enlazamos un programa escrito en un lenguaje como C o C++, el programa entero se convierte en instrucciones ejecutables nativas comprensibles por nuestro motor de ejecucin hardware. Por el contrario, los programas Python se ejecutan en dos fases. Primero, el programa Python se convierte

a una representacin intermedia independiente de la plataforma, conocida como bytecodes. Esta compilacin bytecode tiene lugar automticamente al ejecutar el programa Python, ya sea introduciendo la ruta al intrprete de Python en la primera lnea del archivo fuente, o ejecutndolo como python archivo.py. Las instrucciones en bytecode se interpretan entonces a travs de una aplicacin nativa de la plataforma conocida como mquina virtual de Python. La referencia oficial y tambin la implementacin ms popular de la mquina virtual de Python es CPython; por su nombre es obvio que est escrita en C. Cada una de las instrucciones bytecode invoca a una rutina en C que comprende a su vez varias instrucciones nativas que acometern la tarea encomendada por el bytecode. Este proceso introduce retardos en el tiempo total de ejecucin.

28

Nmero 68

WWW.LINUX- MAGAZINE.ES

Acelerando Python PORTADA

Python es un lenguaje de programacin dinmico, en el que los tipos de datos son objetos, incluso cuando parecen tipos de datos nativos. Ejecutando i = 7; f = 3.14 en el intrprete interactivo de Python, y luego dir(i); dir(f), se pueden ver los mtodos y atributos asociados a i y f. Al declarar sus tipos, se asignan directamente los valores a los distintos objetos del programa Python, ya que slo los valores tienen tipos en Python, no los objetos. Justo lo contrario de lo que hacen los lenguajes estticos como C o C++, en los que primero hay que declarar los tipos de los objetos, ya sean nativos o abstractos, y luego se manipulan stos segn convenga. Adems, se pueden asociar distintos tipos de valores a los objetos Python en tiempo de ejecucin. El runtime de Python, por tanto, tiene que deducir los tipos de los objetos y convertirlos a tipos de datos nativos para conformar finalmente las instrucciones nativas que se ejecutarn en la CPU. Este proceso de deduccin y traduccin es otra de las principales fuentes de sobrecarga en Python. Los objetos Python se asignan y liberan en memoria a travs de un subsistema automtico de asignacin de memoria conocido como gc (Garbage Collector). La actividad de gc tiene lugar despus de un nmero determinado de asignaciones, liberando la memoria asignada a objetos inaccesibles. Durante los ciclos de gc se detienen las dems actividades, de modo que si los ciclos de gc duran mucho, introducen demoras adicionales en el tiempo de ejecucin total del cdigo Python. La mquina virtual de Python se encarga de gestionar adems muchos objetos globales, as como los mdulos externos de cdigo nativo. El intrprete de Python es el que garantiza que a los objetos globales slo acceda un hilo cada vez, proveyendo un bloque exclusivo mutuo conocido como GIL (Global interpreter Lock) [1]. El diseo del intrprete de Python se antoja ms sencillo y simple de mantener, pero como contrapartida, supone an menos velocidad. Debido a GIL, los programas Python no pueden aprovechar las ventajas de ejecutar mltiples hilos de instrucciones en los modernos procesadores multincleo de forma paralela. Por este motivo,

Figura 1: Descargamos Psyco desde el sitio web del proyecto.

aunque se escriban programas Python para que aprovechen las ventajas del procesamiento paralelo, el intrprete de Python slo ejecutar un hilo en cada ciclo de CPU, dejando sin utilizar el resto de ncleos.

Psyco
La forma ms sencilla de acelerar nuestras aplicaciones Python sin tener que tocar el cdigo es mediante el uso de Psyco [2]. Psyco es un mdulo de Python, que con slo importarlo y aadir una lnea o dos, acelerar nuestro cdigo Python existente. Psyco es un proyecto maduro que existe desde hace aos, aunque en estos momentos se encuentra en modo de slo mantenimiento y nicamente disponible para distribuciones Python de 32 bits en arquitecturas x86. Segn su creador, los esfuerzos del trabajo actual y futuro se dirigen hacia una nueva implementacin de Python llamada PyPy. Psyco asegura mejorar la velocidad en un orden de magnitud de 2 a 100 veces, normalmente 4 veces ms rpido que el cdigo fuente Python sin modificar y ejecutado con un intrprete estndar. Est disponible para varias plataformas de SOs, entre las que se cuentan GNU/Linux, BSD, Mac OS/X y Windows. Pysco funciona de modo parecido a como lo hacen los compiladores JIT ( Just in Time ) de otros lenguajes de programacin basados en mquina vir-

tual, como por ejemplo Java. De hecho, Psyco es una especie de compilador JIT que compila los trozos de bytecodes de Python a cdigo mquina nativo en tiempo de ejecucin, aunque hace ms cosas que los compiladores JIT. Crea varias versiones del cdigo nativo compilado para los diferentes tipos de objetos que se corresponden con un trozo de bytecode de Python. Psyco evala los programas Python en tiempo de ejecucin y seala algunas partes de stos como zonas calientes, para las cuales genera instrucciones mquina nativas. Luego, utiliza en las zonas calientes las distintas versiones del cdigo mquina nativo generado. De este modo, trata de adivinar qu partes de nuestros programas Python estn orientadas a mejorar el rendimiento y las compila en trozos de cdigo nativo para proporcionar un rendimiento similar al ofrecido por lenguajes compilados como C o C++. Tambin lleva a cabo varias optimizaciones en tiempo de ejecucin para generar las instrucciones de cdigo nativo ptimas. Psyco est escrito en C, por lo que para compilarlo se necesitan herramientas de compilacin estndar. Tambin son necesarias las cabeceras estndar de Python para instalarlo a partir del tarball con los fuentes. Con el siguiente comando, ejecutado desde la terminal de una mquina Ubuntu de 32 bits, se instalan dichas dependencias:

WWW.LINUX- MAGAZINE.ES

Nmero 68

29

PORTADA Acelerando Python

Figura 2: Google apadrina Unladen Swallow. Un proyecto dedicado a la creacin de una implementacin optimizada de Python.

sudo apt-get install U build-essential && U sudo apt-get install python-dev

Luego, nos dirigimos al sitio oficial del proyecto Psyco (Figura 1), descargamos el ltimo tarball con los fuentes y ejecutamos el siguiente comando:
tar zxvf psyco-version-U src.tar.gz && U cd psyco-version

Finalmente, ejecutamos como root el comando que sigue para instalar Psyco en el sistema:
python setup.py install

Si todo ha ido bien, python -c import psyco no debera mostrar ningn error, lo que significa que ya podemos empezar a jugar con Psyco. Para aplicar Psyco a una aplicacin Python sin ms, basta con aadir las dos siguientes lneas. Un buen lugar donde situarlas es al comienzo del bloque if __main__ == __name__ :
try: import psyco psyco.full() except ImportError: pass

La funcin psyco.full() hace que Psyco ataque a todo el cdigo Python y com-

pile de forma nativa tanto como le sea posible. Es difcil saber cunto mejora Psyco el rendimiento, debido a los complicados mecanismos que utiliza para generar las versiones nativas de los programas Python. An as, existen frmulas para calcular los picos de mejora ms importantes. Antes de nada, Psyco es til principalmente para programas Python donde la CPU es un factor crtico (es decir, con muchas iteraciones, clculos matemticos, listas extensas, cadenas y operaciones numricas). Psyco no tiene por qu resultar til para cdigo Python en el cual el factor crtico es I/O (es decir, con esperas a eventos de red, lecturas y escrituras a disco, operaciones de bloqueo, etc.), dado que el rendimiento en estos casos est condicionado por el GIL de Python (Global Interpreter Lock), y Psyco no tiene control sobre l. Puesto que Psyco genera varias versiones del cdigo nativo optimizadas para diferentes tipos de objetos, necesita una gran cantidad de memoria adicional. Esto supone una merma en el rendimiento de los programas si se utiliza en aplicaciones Python completas que no son candidatas adecuadas. Por todo ello, slo se debe usar psyco.full() en aquellos casos en los que los programas son cortos o cuando se est seguro de que los problemas de rendimiento vienen dados por el uso de la CPU.

En lugar de psyco.full(), se usa psyco.profile() para indicar a Psyco que no acte sobre el programa Python completo, sino que antes debe analizarlo para luego compilar solamente las partes crticas desprendidas del anlisis. La funcin profile() es la opcin a elegir en el caso de programas de gran tamao. Se le puede pasar adems un valor de marca de agua entre 0.0 y 1.0, que indica la proporcin de funciones compiladas. La marca de agua predeterminada est en 0.09, y es el valor que adopta profile() cuando no recibe ningn parmetro. Las funciones de Psyco full() y profile() aceptan un argumento ms que especifica el lmite en Kilobytes por debajo del cual se compilan las funciones. Psyco proporciona adems una funcin log(). El siguiente cdigo Psyco habilita el logging y la compilacin basada en anlisis del perfil para las funciones que consuman al menos un 7% del tiempo y menos de 200 KB por funcin:
psyco.log() psyco.profile(0.07, memory=200)

A travs de psyco.bind() y psyco.proxy() es posible controlar la seleccin de las funciones que compila Psyco. Ambas funciones aceptan el nombre de la funcin determinada a compilar, pero proxy() slo compila la instancia especfica de la funcin que recibe como argumento y no todas las instancias de la funcin llamadas durante la ejecucin del programa Python. Bind() compila la funcin original que recibe, as como las funciones llamadas en el nombre de funcin que recibe como argumento. En el siguiente ejemplo, todas las instancias de funcion1, as como las funciones internas a las que a su vez llama, se compilan nativamente, aunque slo se compila nativamente la instancia g de funcion2:
psyco.bind(funcion1) g = psyco.proxy(funcion2) g(args) funcion2(args)

Slo con unas pocas lneas de cdigo y apenas conocimientos previos acerca de la naturaleza de los programas Python se puede mejorar el rendimiento mediante Psyco. Incluso es posible

30

Nmero 68

WWW.LINUX- MAGAZINE.ES

Acelerando Python PORTADA

determinar cules son los modos de Psyco que nos vienen bien con slo probarlos y comparando los resultados. Psyco contiene muchos programas Python de prueba en el subdirectorio test dentro del directorio de los fuentes. Para ms informacin, consultar la documentacin dispuesta en el sitio oficial del proyecto.

den Swallow se puede encontrar informacin detallada; y tambin el juego de pruebas en Python para medir la eficacia de Unladen Swallow y CPython.

Shed Skin
Shed Skin [4] mejora el rendimiento del cdigo Python mediante un mtodo distinto. Toma los programas Python escritos en un subconjunto esttico del lenguaje Python estndar y genera el correspondiente cdigo C++ optimizado. Este cdigo C++ generado se podra compilar como una aplicacin nativa, o bien podra importarse el mdulo como extensin de programas Python de mayor envergadura. De este modo, Shed Skin puede mejorar la velocidad de ejecucin de aquellos programas que hacen uso intensivo de CPU. Actualmente, Shed Skin se encuentra en estado experimental y soporta slo unos 20 mdulos de la librera estndar, aunque es un proyecto muy prometedor. En la pgina del proyecto se pueden encontrar paquetes .deb y .rpm de Shed Skin, adems del tarball con los fuentes. Para instalar Shed Skin desde los fuentes, los prerrequisitos son g++, el recolector de basura Boehm [5] y la librera PCRE [6]. En Debian se pueden instalar estos componentes muy fcilmente desde la lnea de comandos con:
sudo apt-get install g++ U libgc-dev libpcre3-dev

Unladen Swallow
El fundador de Python, Guido van Rossum, trabaja para Google, y Python junto con C++ y Java es uno de los lenguajes de programacin utilizados all oficialmente. Uno de los resultados del trabajo de van Rossum es Unladen Swallow [3], una rama dedicada a la optimizacin del cdigo base de Python (Figura 2). El objetivo principal de Unladen Swallow es el de mantener una compatibilidad completa con CPython y sus libreras, al tiempo que proporciona un incremento en el rendimiento. Unladen Swallow est basado en Python 2.6.1 y slo cambia el runtime de Python. Actualmente, YouTube hace uso intensivo de Unladen Swallow. El proyecto Unladen Swallow ha implementado la compilacin JIT para mejorar el rendimiento de los programas Python. La implementacin actual del runtime de Unladen Swallow convierte los bytecodes de Python de todas las funciones calientes primero a LLVM (Low Level Virtual Machine) IR (Intermediate Representation), y ste a su vez se compila a cdigo mquina nativo. A largo plazo, los planes pasan por cambiar la mquina virtual de CPython, basada en stack, a la mquina virtual sobre cdigo LLVM basada en registros para conseguir una mayor aceleracin. El proyecto ha aadido adems muchas mejoras al recolector de basura de CPython para que realice menos ciclos de recoleccin, y rebajar as los retardos ocasionados por la recoleccin de basura. Unladen Swallow es un proyecto en curso, por lo que hay que compilarlo desde los fuentes tras obtener el cdigo desde el repositorio de subversin del proyecto. Los prerrequisitos para su compilacin son llvm y clang (ms las herramientas estndar de compilacin utilizadas con Psyco para compilar llvm y clang). En el sitio del proyecto Unla-

Utiliza tcnicas de inferencia de tipos para determinar los tipos usados en los programas Python y realiza anlisis iterativos sobre los programas para ver qu valores se les asignan a los distintos objetos para deducir de ese modo cules sern sus tipos estticos. Siendo as, no es posible mezclar diferentes tipos asignados a una misma variable. Adems nos fuerza a usar solamente tipos similares para los elementos de las distintas colecciones de Python (tuple, list, set, etc.). El uso bsico de Shed Skin es:
shedskin archivo.py

Tambin se pueden compilar gc y libpcre en plataformas para las que no existen paquetes precompilados, descargando los tarballs y siguiendo las instrucciones de compilacin. Una vez satisfechos todos los requisitos, descargamos el ltimo tarball de Shed Skin desde el sitio web del proyecto y ejecutamos el siguiente comando desde una consola de texto:
tar zxvf shedskin-version.tgz U && cd shedskin-version

Shed Skin crea archivo.hpp, archivo.cpp y Makefile en el directorio actual. Tambin proporciona algunos switches para controlar la forma en la que se generan los archivos resultantes (por ejemplo, un archivo Python anotado se genera con -a). Finalmente, se puede invocar el makefile generado para compilar el ejecutable correspondiente al cdigo Python a partir del cual se gener. Existen muchos programas de prueba proporcionados en forma de archivo tar en el sitio web del proyecto Shed Skin. En l se hace alusin a mejoras en el rendimiento de los programas de prueba de 2 a 200 veces en comparacin a CPython. Descargamos shedskin-examples-version.tgz desde el sitio web y ejecutamos los siguientes comandos desde la terminal:
tar zxvf shedskin-examples-U version.tgz && U cd shedskin-examples-version

Para probar el programa Python jpeg-tobmp, compilamos el ejecutable nativo con:


shedskin -m jpg2bmp.mk U TonyJpegDecoder.py && U make -f jpg2bmp.mk

Finalmente, ejecutamos como root para instalar Shed Skin en el sistema:


python setup.py install

Shed Skin traduce los tipos implcitos de Python a tipos explcitos de C++.

Ahora comparamos el rendimiento de la versin en Python y de la versin compilada del programa con los comandos time python TonyJpegDecoder.py y time ./TonyJpegDecoder, respectivamente. En nuestras pruebas, la versin compilada del ejemplo de TonyJpegDecoder era 1.5

WWW.LINUX- MAGAZINE.ES

Nmero 68

31

PORTADA Acelerando Python

extensin de los fuentes de Wirbel es .w y no .py, y si tratamos de compilar los archivos .py con el compilador de Wirbel, se mostrar un mensaje de error. Otra diferencia es que no hace falta importar nada en los fuentes de Wirbel, ya que no entiende la declaracin import. Wirbel busca por s mismo todo lo que necesita. Soporta la sobrecarga de funciones; algo que tampoco est soportado en Python. Su funcin print utiliza parntesis, como en Python 3.0. Wirbel incluye muchos ejemplos y pruebas; para verlo en accin podemos ir a los ejemplos y medir la mejora del rendimiento en comparacin a las mismas aplicaciones escritas en cdigo Python.

Conclusin
Figura 3: El sitio web del proyecto Wirbel enumera las bondades de ste (y resalta tambin algunas limitaciones).

veces ms rpida que su homlogo en Python. Hicimos tambin otras pruebas; la versin compilada de chess.py era 12 veces ms rpida, mientras que la de sudoku1.py lo era 31 veces.

tar zxvf wirbel-version.tar.gz U && cd wirbel-version

Wirbel: Lenguaje Compilado Estilo Python


Wirbel [7] es otro proyecto experimental para quienes buscan mejorar el rendimiento de sus programas Python. Segn la introduccin mostrada en el sitio web de Wirbel (Figura 3), Wirbel es un nuevo lenguaje de programacin. Posee una sintaxis y una semntica parecidas a las de de Python pero a diferencia de Python Wirbell es un lenguaje compilable a cdigo mquina nativo. Wirbel es como Shedskin en lo que se refiere a uso de tipos de datos estticos, y tambin usa inferencia de tipos para deducir la informacin sobre los tipos de datos y producir cdigo ejecutable. Es un nuevo proyecto con un soporte de libreras limitado, por lo que an est lejos de soportar la ingente cantidad de funcionalidades de Python, aunque podra resultar til para escribir pequeos programas con una sintaxis parecida a la de Python. Para instalar Wirbel, descargamos el ltimo tarball con los fuentes desde el sitio web del proyecto y ejecutamos lo siguiente desde una consola de comandos:

Luego, ejecutamos ./configure && make para compilarlo. Si la compilacin termina con xito, instalamos con make install, contando con los privilegios de root necesarios. En nuestras pruebas surgieron algunos problemas en las mquinas con Puppy de 32 bits y Ubuntu de 64 bits, debido a la eliminacin de algunas cabeceras en las ltimas versiones de g++. Aadimos las cabeceras #include <cstdio> en los archivos src/Type.cc y src/Location.cc, e #include <stdint.h> en baustones/ httpd/HTTPRequest.h. Estos subdirectorios se hallan en el directorio de fuentes de nivel superior. El autor de Wirbel ha sido informado de ello, por lo que esperamos que est solucionado en la prxima publicacin del proyecto. Una vez instalado, deberan estar disponibles dos nuevos comandos desde la terminal, el compilador de Wirbel wic y una utilidad que compila y enlaza el cdigo .w y ejecuta el cdigo ejecutable. Se puede aadir la ruta absoluta de Wirbel (con !#) a los archivos .w para ejecutarlos como si de scripts se tratase. El comando wic acepta muchas opciones, que podemos consultar mediante su pgina de manual, con man wic. Wirbel presenta otras diferencias con Python aparte de la naturaleza esttica de los tipos de datos. Antes de nada, la

Si est cansado de esperar a sus programas escritos en Python, debera probar estas innovadoras herramientas de optimizacin. Psyco mejora el rendimiento muy significativamente con slo aadir un par de lneas. Unladen Swallow es el nuevo runtime de Python con turbo que optimiza CPython sin eliminar la compatibilidad retroactiva. Shed Skin y Wirbel son proyectos experimentales que se centran en un subconjunto de cdigo Python esttico para proporcionar un rendimiento equiparable al cdigo I nativo.

RECURSOS
[1] Python GIL: http://blip.tv/file/2232410 [2] Pgina del proyecto Psyco: http:// psyco.sourceforge.net/ [3] Pgina del proyecto Unladen Swahttp://code.google.com/p/ llow: unladen-swallow/ [4] Pgina del proyecto Shedskin: http:// code.google.com/p/shedskin/ [5] Pgina del recolector Boehm: http:// www.hpl.hp.com/personal/ Hans_Boehm/gc/ [6] Pgina de la librera PCRE: http:// www.pcre.org/ [7] Pgina del proyecto Wirbel: http:// mathias-kettner.de/wirbel_index. html

Ankur Kumar Sharma es desarrollador de software e investigador. Le gusta tararear y tocar canciones clsicas de rock con su guitarra, adems de leer libros de autoayuda, escribir y explorar las cosas interesantes de la vida. Puede ver su blog en http://www. richnusgeeks.com.

32

Nmero 68

WWW.LINUX- MAGAZINE.ES

EL AUTOR

También podría gustarte