2008-09-26 9 views
105

¿Qué tan factible sería compilar Python (posiblemente a través de una representación C intermedia) en código de máquina?¿Es factible compilar Python para código de máquina?

Presumiblemente, necesitaría vincular a una biblioteca de tiempo de ejecución de Python, y cualquier parte de la biblioteca estándar de Python que fuera Python necesitaría compilarse (y vincularse también).

Además, necesitaría agrupar el intérprete de Python si deseaba hacer una evaluación dinámica de las expresiones, pero quizás un subconjunto de Python que no lo permitiera aún sería útil.

¿Proporcionaría alguna velocidad y/o ventajas de uso de memoria? Presumiblemente, el tiempo de inicio del intérprete de Python se eliminaría (aunque las bibliotecas compartidas aún necesitarían cargarse al inicio).

+0

Por cierto, su pregunta sería en mi humilde opinión más clara si usted pidió un "código de máquina" en lugar de código objeto. –

+0

Gracias, he hecho ese cambio. –

Respuesta

19

Pruebe ShedSkin compilador Python-to-C++, pero está lejos de ser perfecto. También está Psyco - Python JIT si solo se necesita aceleración. Pero en mi humilde opinión esto no vale la pena el esfuerzo. Para las partes críticas de la velocidad del código, la mejor solución sería escribirlas como extensiones C/C++.

+4

FYI, ShedSkin eliminó el soporte de Windows. – sorin

+2

@sorin: bueno, hoy es compatible con Windows ... http://code.google.com/p/shedskin/downloads/detail?name=shedskin-0.9.1.exe & can = 2 & q = –

+0

La mejor solución, speedwise, podría ser [PyPy] (http://morepypy.blogspot.nl/2011/08/pypy-is-faster-than-c-again-string.html). –

8

Esto puede parecer razonable a primera vista, sin embargo, hay muchas cosas ordinarias en Python que no se pueden asignar directamente a una representación en C sin tener que soportar gran parte del soporte de tiempo de ejecución de Python. Por ejemplo, me viene a la mente el tipado de patos. Muchas funciones en Python que leen entrada pueden tomar un archivo o un objeto similar a un archivo, siempre que admita ciertas operaciones, por ejemplo. read() o readline(). Si piensa en qué se necesitaría para asignar este tipo de soporte a C, comenzará a imaginar exactamente el tipo de cosas que el sistema de tiempo de ejecución de Python ya hace.

Hay utilidades como py2exe que agruparán un programa Python y el tiempo de ejecución en un único ejecutable (en la medida de lo posible).

+0

¿Qué pasa si mi objetivo es asegurarme de que el código compila, porque los lenguajes compilados estáticamente son (al menos en mi opinión) menos propensos a estallar en el tiempo de ejecución? ¿Es posible determinar que alguna expresión 'foo.x' no funcionará porque' foo' no tendrá 'x' en el momento en que se llama. ¿Hay alguna verificación de código estático para Python? Python se puede compilar en un ensamblado .Net ... –

2

Psyco es un tipo de compilador just-in-time (JIT): compilador dinámico para Python, ejecuta el código 2-100 veces más rápido, pero necesita mucha memoria.

En resumen: ejecuta su software Python existente mucho más rápido, sin cambios en su fuente, pero no se compila al código objeto de la misma forma que un compilador de C.

2

Jython tiene un compilador que apunta al bytecode de JVM. ¡El bytecode es completamente dinámico, al igual que el lenguaje Python mismo! Muy genial. (Sí, ya que alude la respuesta de Greg Hewgill, el código de bytes hace utilizar el tiempo de ejecución de Jython, por lo que el archivo jar Jython se debe distribuir con su aplicación.)

13

PyPy es un proyecto de volver a implementar Python en Python, utilizando la compilación de código nativo como una de las estrategias de implementación (otras son una VM con JIT, usando JVM, etc.). Sus versiones C compiladas son más lentas que CPython en promedio, pero mucho más rápidas para algunos programas.

Shedskin es un compilador experimental de Python a C++.

Pyrex es un lenguaje especialmente diseñado para escribir módulos de extensión de Python. Está diseñado para cerrar la brecha entre el mundo agradable, de alto nivel y fácil de usar de Python y el desordenado mundo de bajo nivel de C.

+3

Cython es la horquilla amigable de Pyrex más ampliamente utilizada y desarrollada más activamente. –

44

Como lo dice @Greg Hewgill, hay buenas razones por las cuales esto no siempre es posible Sin embargo, ciertos tipos de código (como el código muy algorítmico) se pueden convertir en códigos de máquina "reales".

Hay varias opciones:

  • Uso Psyco, que emite el código máquina de forma dinámica. Sin embargo, debes elegir cuidadosamente qué métodos/funciones convertir.
  • Uso Cython, que es un Python- como lenguaje que se compila en una extensión de Python C
  • Uso PyPy, que tiene un traductor de RPython (un subconjunto restringido de Python que no admite algunas de las la mayoría de las características "dinámicas" de Python) a C o LLVM.
    • PyPy es todavía muy experimental
    • no todas las extensiones estarán presentes

Después de eso, puede utilizar uno de los paquetes existentes (congelación, py2exe, PyInstaller) para poner todo en un binario

En general: no hay una respuesta general para su pregunta. Si tiene un código de Python que es crítico para el rendimiento, intente utilizar tanta funcionalidad incorporada como sea posible (o pregunte "¿Cómo hago para que mi código Python sea más rápido?"). Si eso no ayuda, intente identificar el código y transferirlo a C (o Cython) y usar la extensión.

+1

Pypy es el sucesor de Psyco – bcattle

9

Pyrex es un subconjunto del lenguaje Python que se compila en C, hecho por el tipo que primero construyó list comprehensions para Python. Se desarrolló principalmente para envoltorios de construcción, pero se puede utilizar en un contexto más general. Cython es una horquilla de pyrex mantenida más activamente.

+2

Cython es la horquilla amigable de Pyrex más ampliamente utilizada y desarrollada de forma más activa. –

+0

Ese es un buen punto. Actualizado. – ConcernedOfTunbridgeWells

2

La respuesta es "Sí, es posible". Puede tomar el código Python e intentar compilarlo en el código C equivalente utilizando la API CPython. De hecho, solía haber un proyecto Python2C que hacía justamente eso, pero no he oído hablar de él en muchos años (en el Python 1.5 días es la última vez que lo vi)

Puedes intentar traducir el código de Python en C nativo tanto como sea posible, y recurra a la API de CPython cuando necesite funciones de Python reales. He estado jugando con esa idea el último mes o dos. Sin embargo, es un montón de trabajo, y una gran cantidad de características de Python son muy difíciles de traducir en C: funciones anidadas, generadores, cualquier cosa menos simples clases con métodos simples, cualquier cosa que implique la modificación de módulos globales desde fuera del módulo, etc. , etc.

15

py2c (http://code.google.com/p/py2c) puede convertir el código python en c/C++ Soy el desarrollador solo de py2c.

+0

Esto parece una herramienta útil. ¿Todavía se mantiene? –

+0

@AndersonGreen Está en una etapa de desarrollo inicial la última vez que trabajé en él (probablemente similar ahora). Me fui del proyecto porque I̶'̶m̶ ̶b̶u̶s̶y̶ Soy perezoso. Si no ha notado el texto "Importante", se ha movido a GitHub ahora. –

+0

El enlace apunta a [instalador no sustituido] (https://github.com/RamchandraApte/unvanquished-installer/issues), que parece ser un proyecto diferente. ¿Todavía está disponible py2c en GitHub? –

10

Nuitka es un compilador de Python a C++ que enlaza con libpython. Parece ser un proyecto relativamente nuevo. El autor reclama un speed improvement sobre CPython en el benchmark pystone.

2

Esto no compila Python al código de máquina. Pero permite crear una biblioteca compartida para llamar al código de Python.

Si lo que estás buscando es una manera fácil de ejecutar código Python desde C sin depender de cosas execp. Puede generar una biblioteca compartida desde el código de Python incluido con unas pocas llamadas al Python embedding API. Bueno, la aplicación es una biblioteca compartida, una .so que puede usar en muchas otras bibliotecas/aplicaciones.

Aquí hay un ejemplo simple que crea una biblioteca compartida, que puede vincular con un programa C. La biblioteca compartida ejecuta el código de Python.

El archivo pitón que se ejecutará es pythoncalledfromc.py:

# -*- encoding:utf-8 -*- 
# this file must be named "pythoncalledfrom.py" 

def main(string): # args must a string 
    print "python is called from c" 
    print "string sent by «c» code is:" 
    print string 
    print "end of «c» code input" 
    return 0xc0c4 # return something 

se puede probar con python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO'). Es seria:

python is called from c 
string sent by «c» code is: 
HELLO 
end of «c» code input 

La biblioteca compartida se define mediante la siguiente por callpython.h:

#ifndef CALL_PYTHON 
#define CALL_PYTHON 

void callpython_init(void); 
int callpython(char ** arguments); 
void callpython_finalize(void); 

#endif 

El asociada callpython.c es:

// gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so 

#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <python2.7/Python.h> 

#include "callpython.h" 

#define PYTHON_EXEC_STRING_LENGTH 52 
#define PYTHON_EXEC_STRING "import pythoncalledfromc; pythoncalledfromc.main(\"%s\")" 


void callpython_init(void) { 
    Py_Initialize(); 
} 

int callpython(char ** arguments) { 
    int arguments_string_size = (int) strlen(*arguments); 
    char * python_script_to_execute = malloc(arguments_string_size + PYTHON_EXEC_STRING_LENGTH); 
    PyObject *__main__, *locals; 
    PyObject * result = NULL; 

    if (python_script_to_execute == NULL) 
    return -1; 

    __main__ = PyImport_AddModule("__main__"); 
    if (__main__ == NULL) 
    return -1; 

    locals = PyModule_GetDict(__main__); 

    sprintf(python_script_to_execute, PYTHON_EXEC_STRING, *arguments); 
    result = PyRun_String(python_script_to_execute, Py_file_input, locals, locals); 
    if(result == NULL) 
    return -1; 
    return 0; 
} 

void callpython_finalize(void) { 
    Py_Finalize(); 
} 

Se puede compilar con el siguiente comando :

gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so 

Crear un archivo llamado callpythonfromc.c que contiene lo siguiente:

#include "callpython.h" 

int main(void) { 
    char * example = "HELLO"; 
    callpython_init(); 
    callpython(&example); 
    callpython_finalize(); 
    return 0; 
} 

compilarlo y ejecute:

gcc callpythonfromc.c callpython.so -o callpythonfromc 
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc 

Este es un ejemplo muy básico. Puede funcionar, pero dependiendo de la biblioteca puede ser difícil serializar las estructuras de datos C a Python y desde Python a C. Las cosas pueden automatizarse un poco ...

Nuitka puede ser útil.

También hay numba pero ambos no pretenden hacer exactamente lo que usted quiere. Es posible generar un encabezado C a partir del código Python, pero solo si especifica cómo convertir los tipos Python a tipos C o puede inferir esa información. Ver python astroid para un analizador Python ast.

Cuestiones relacionadas