Pregunta

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

Es de suponer que tendría que vincularse a una biblioteca de tiempo de ejecución de Python, y cualquier parte de la biblioteca estándar de Python que fuera Python en sí tendría que ser compilada (y enlazada) también.

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

¿Brindaría alguna ventaja de velocidad y / o uso de memoria? Presumiblemente, el tiempo de inicio del intérprete de Python se eliminaría (aunque las bibliotecas compartidas todavía necesitarían cargarse durante el inicio).

¿Fue útil?

Solución

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

Otros consejos

Como lo dice @Greg Hewgill, hay buenas razones por las que esto no siempre es posible. Sin embargo, ciertos tipos de código (como el código muy algorítmico) se pueden convertir en " real " codigo de maquina.

Hay varias opciones:

  • Utilice Psyco , que emite el código de máquina dinámicamente. Sin embargo, debes elegir cuidadosamente qué métodos / funciones convertir.
  • Use Cython , que es un lenguaje Python- like que se compila en un Python Extensión C
  • Use PyPy , que tiene un traductor de RPython (un subconjunto restringido de Python que sí lo hace no admite algunas de las funciones más dinámicas de Python a C o LLVM.
    • PyPy sigue siendo altamente experimental
    • no todas las extensiones estarán presentes

Después de eso, puedes usar uno de los paquetes existentes (congelar, 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 la mayor funcionalidad integrada posible (o pregunte una pregunta "¿Cómo puedo hacer que mi código de Python sea más rápido?"). Si eso no ayuda, intente identificar el código y portarlo a C (o Cython) y use la extensión.

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

Nuitka es un compilador de Python a C ++ que se vincula con libpython. Parece ser un proyecto relativamente nuevo. El autor reclama una mejora de velocidad sobre CPython en el punto de referencia de pystone.

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

Shedskin es un compilador experimental de Python-to-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 agradable mundo de Python, de alto nivel y fácil uso, y el mundo desordenado de bajo nivel de C.

Pyrex es un subconjunto del lenguaje Python que compila a C, hecho por el chico que primero construyó enumera las comprensiones para Python. Fue desarrollado principalmente para la construcción de envolturas, pero se puede utilizar en un contexto más general. Cython es una bifurcación de pyrex con un mantenimiento más activo.

Esto puede parecer razonable a primera vista, sin embargo, hay muchas cosas comunes en Python que no se pueden asignar directamente a una representación en C sin tener que cargar con gran parte del soporte en tiempo de ejecución de Python. Por ejemplo, la escritura de pato viene a la mente. Muchas funciones en Python que leen la entrada pueden tomar un objeto o similar a un archivo , siempre que sea compatible con ciertas operaciones, por ejemplo. read () o readline (). Si piensa en lo que se necesitaría para asignar este tipo de soporte a C, comienza a imaginar exactamente el tipo de cosas que ya hace el sistema de tiempo de ejecución de Python.

Existen utilidades como py2exe que agruparán un programa y tiempo de ejecución de Python en un solo ejecutable (hasta ahora) como sea posible).

Algunas referencias adicionales:

Jython tiene un compilador que apunta a bytecode JVM. El bytecode es completamente dinámico, al igual que el propio lenguaje Python. Muy genial. (Sí, como alude la respuesta de Greg Hewgill, el código de bytes utiliza el tiempo de ejecución de Jython, por lo que el archivo jar de Jython debe distribuirse con su aplicación).

Psyco es un tipo de compilador JIT (JIT): compilador dinámico para Python, el código se ejecuta de 2 a 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 compila código de objeto de la misma forma que lo haría un compilador de C

La respuesta es " Sí, es posible " ;. Podría tomar el código Python e intentar compilarlo en el código C equivalente utilizando la API de CPython. De hecho, solía haber un proyecto de Python2C que hizo exactamente eso, pero no lo he escuchado en muchos años (desde la última vez que lo vi en Python 1.5 días)

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

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

Si lo que buscas es una manera fácil de ejecutar el código Python desde C sin depender de cosas de execp. Podría generar una biblioteca compartida a partir de código python envuelto con unas pocas llamadas a API de incrustación de Python . Bueno, la aplicación es una biblioteca compartida, que puede usar en muchas otras bibliotecas / aplicaciones.

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

El archivo python 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

Puedes probarlo con python2 -c " import pythoncalledfromc; pythoncalledfromc.main ('HELLO') . Saldrá:

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

La biblioteca compartida se definirá de la siguiente manera mediante callpython.h :

#ifndef CALL_PYTHON
#define CALL_PYTHON

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

#endif

El callpython.c asociado 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();
}

Puedes compilarlo con el siguiente comando:

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

Cree un archivo llamado callpythonfromc.c que contenga lo siguiente:

#include "callpython.h"

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

Compílalo y ejecuta:

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 de C a Python y de Python a C. Las cosas se pueden automatizar de alguna manera ...

Nuitka puede ser útil.

También hay numba pero ambos no pretenden hacer lo que quieres exactamente. 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 si puede inferir esa información. Vea Python Astroid para un analizador Python Ast.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top