將Python(可能通過中間C代表)編譯成機器代碼有多大的可行性?將Python編譯爲機器碼是否可行?
大概就需要鏈接到一個Python運行時庫,併爲Python的本身將需要編譯(和鏈接中)太Python標準庫的任何部分。
此外,你需要,如果你想要做表達式的動態評價,但也許Python中的一個子集,並沒有讓這仍然是有用的捆綁Python解釋器。
它會提供任何速度和/或內存使用優勢?據推測,Python解釋器的啓動時間將被消除(儘管共享庫在啓動時仍然需要加載)。
將Python(可能通過中間C代表)編譯成機器代碼有多大的可行性?將Python編譯爲機器碼是否可行?
大概就需要鏈接到一個Python運行時庫,併爲Python的本身將需要編譯(和鏈接中)太Python標準庫的任何部分。
此外,你需要,如果你想要做表達式的動態評價,但也許Python中的一個子集,並沒有讓這仍然是有用的捆綁Python解釋器。
它會提供任何速度和/或內存使用優勢?據推測,Python解釋器的啓動時間將被消除(儘管共享庫在啓動時仍然需要加載)。
嘗試ShedSkin的Python到C++編譯器,但它遠非完美。如果只需要加速,還有Psyco - Python JIT。但恕我直言,這是不值得的努力。對於速度至關重要的代碼部分,最好的解決方案是將它們編寫爲C/C++擴展。
僅供參考,ShedSkin放棄了對Windows的支持。 – sorin 2010-04-20 16:02:47
@sorin:好吧,今天它支持Windows ... http://code.google.com/p/shedskin/downloads/detail?name=shedskin-0.9.1。exe&can = 2&q = – 2012-01-16 16:19:07
速度最好的解決方案仍然可以是[PyPy](http://morepypy.blogspot.nl/2011/08/pypy-is-faster-than-c-again-string.html)。 – 2012-11-12 14:10:42
這似乎是合理的第一眼,但有Python中的很多普通的事情沒有直接可映射到一個C表示沒有帶過很多Python運行時支持。例如,鴨子打字想到。在Python中,讀取輸入的許多函數可以採用文件或類似文件的對象,只要它支持某些操作,例如。 read()或readline()。如果您考慮將這種類型的支持映射到C需要花費多少時間,您就開始想象Python運行時系統已經完成的各種事情。
有實用程序,如py2exe將捆綁Python程序和運行成單個可執行(儘可能)。
如果我的目標是確保代碼編譯,如果靜態編譯語言(至少在我看來)在運行時不太可能爆炸,那該怎麼辦?是否有可能確定某些`foo.x`表達式不起作用,因爲`foo`在被調用時不會有`x`。是否有Python的靜態代碼檢查器? Python可以被編譯成一個.Net程序集...... – 2012-10-20 04:10:27
Psyco是一種即時(JIT)編譯器:用於Python的動態編譯器,運行速度快2-100倍,但需要大量內存。
總之:它運行得更快現有的Python軟件,在你的源沒有變化,但它不會編譯爲對象代碼的方式,C編譯器會。
Jython有一個針對JVM字節碼的編譯器。字節碼是完全動態的,就像Python語言本身一樣!很酷。 (是的,正如Greg Hewgill的回答所暗示的,字節碼確實使用Jython運行時,所以Jython jar文件必須與您的應用程序一起分發。)
正如@Greg Hewgill所說,它有很好的理由並不總是可能的。但是,某些類型的代碼(如非常算法代碼)可以轉化爲「真實」機器代碼。
有幾種選擇:
之後,你可以使用現有的包之一(凍結,Py2exe,PyInstaller)把一切都成一個二進制。
總而言之:你的問題沒有一般的答案。如果您的Python代碼對性能至關重要,請儘量使用盡可能多的內置功能(或者詢問「如何更快地創建我的Python代碼」問題)。如果這沒有幫助,請嘗試識別代碼並將其移植到C(或Cython)並使用擴展名。
Pyrex是編譯爲C的Python語言的一個子集,由首先爲Python創建list comprehensions的人完成。它主要是爲建築包裝材料開發的,但可以用在更一般的環境中。 Cython是pyrex更加積極維護的一個分支。
答案是「是的,這是可能的」。您可以使用Python代碼並嘗試使用CPython API將其編譯爲等效的C代碼。事實上,過去有一個Python2C項目可以做到這一點,但我多年沒聽說過(回到Python 1.5天是我上次看到它的時候)。
您可以嘗試翻譯將Python代碼儘可能地轉換爲本地C,並在您需要實際的Python功能時回退到CPython API。上個月我一直在玩這個想法。然而,這是一項非常多的工作,並且大量的Python特性很難轉化爲C:嵌套函數,生成器,除了簡單類的簡單類之外的任何東西,涉及從模塊外部修改模塊全局變量的任何內容等等。等。
py2c(http://code.google.com/p/py2c)可以將python代碼轉換爲c/C++ 我是py2c的獨立開發者。
Nuitka是一個Python到C++編譯器,鏈接到libpython。這似乎是一個相對較新的項目。作者在pystone基準測試中聲明瞭CPython的speed improvement。
這不會將Python編譯爲機器碼。但是允許創建一個共享庫來調用Python代碼。
如果你正在尋找的是一個簡單的方法來從C運行Python代碼而不依賴於execp的東西。您可以從包含幾個調用Python embedding API的Python代碼生成共享庫。那麼這個應用程序就是一個共享庫,你可以在許多其他的庫/應用程序中使用它。
下面是一個簡單的例子,它創建一個共享庫,您可以鏈接到一個C程序。共享庫執行Python代碼。
將要執行的Python文件是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
您可以python2 -c "import pythoncalledfromc; pythoncalledfromc.main('HELLO')
嘗試。它會輸出:
python is called from c
string sent by «c» code is:
HELLO
end of «c» code input
共享庫將通過以下來定義由callpython.h
:
#ifndef CALL_PYTHON
#define CALL_PYTHON
void callpython_init(void);
int callpython(char ** arguments);
void callpython_finalize(void);
#endif
關聯callpython.c
是:
// 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();
}
可以用下面的命令編譯它:
gcc `python2.7-config --ldflags` `python2.7-config --cflags` callpython.c -lpython2.7 -shared -fPIC -o callpython.so
創建一個名爲callpythonfromc.c
文件,該文件包含以下內容:
#include "callpython.h"
int main(void) {
char * example = "HELLO";
callpython_init();
callpython(&example);
callpython_finalize();
return 0;
}
編譯並運行:
gcc callpythonfromc.c callpython.so -o callpythonfromc
PYTHONPATH=`pwd` LD_LIBRARY_PATH=`pwd` ./callpythonfromc
這是一個非常簡單的例子。它可以工作,但取決於庫,它可能仍然很難將C數據結構序列化爲Python,並且從Python到C也很難。事情可能會有些自動化...事實可能會有所自動化...
Nuitka可能會有所幫助。
也有numba但他們都沒有打算做你想要的東西。只有在指定如何將Python類型轉換爲C類型或可以推斷該信息時,纔可以從Python代碼生成C頭文件。有關Python ast分析器,請參閱python astroid。
一些額外的引用:
https://github.com/dropbox/pyston是Python的JIT編譯器通過Dropbox的
http://pythran.readthedocs.io/ developped是一個編譯時的python C++翻譯爲科學計算
https://github.com/cosmo-ethz/hope是用於科學計算的JIT python to C++翻譯器
順便說一句,如果您要求「機器代碼」而不是目標代碼,您的問題將會變得更加清晰。 – 2008-09-26 10:20:32
謝謝,我做了這個改變。 – 2009-08-13 14:45:39