将Python编译为机器代码是否可行?

时间:2020-03-06 14:46:31  来源:igfitidea点击:

将Python(可能通过中间C表示形式)编译为机器代码的可行性如何?

大概需要链接到Python运行时库,并且Python标准库中Python本身的任何部分也需要进行编译(并链接)。

另外,如果我们想对表达式进行动态求值,则需要捆绑Python解释器,但是也许不允许这样做的Python子集仍然有用。

它会提供任何速度和/或者内存使用优势吗?大概可以省去Python解释器的启动时间(尽管共享库在启动时仍需要加载)。

解决方案

乍看之下这似乎是合理的,但是在Python中,有很多普通的东西不能直接映射到C表示形式,而又不会继承大量的Python运行时支持。例如,想到鸭式打字。 Python中许多读取输入的函数可以采用文件或者类似文件的对象,只要它支持某些操作即可。 read()或者readline()。如果考虑将这种类型的支持映射到C所需要的内容,那么我们将开始完全想象Python运行时系统已经完成的各种工作。

有诸如py2exe之类的实用程序,它将Python程序和运行时捆绑到一个可执行文件中(尽可能)。

Psyco是一种即时(JIT)编译器:适用于Python的动态编译器,代码运行速度快2到100倍,但需要大量内存。

简而言之:它可以更快地运行现有的Python软件,而无需更改源代码,但是它无法像C编译器那样编译为目标代码。

尝试使用ShedSkin从Python到C ++的编译器,但这远非完美。如果只需要加速,也可以使用Psyco Python JIT。但是恕我直言,这是不值得的努力。对于速度至关重要的代码部分,最好的解决方案是将它们编写为C / C ++扩展。

Jython有一个针对JVM字节码的编译器。字节码是完全动态的,就像Python语言本身一样!很酷。 (是的,正如Greg Hewgill的答案所暗示的那样,字节码确实使用了Jython运行时,因此Jython jar文件必须随应用程序一起分发。)

PyPy是一个在Python中重新实现Python的项目,使用对本机代码的编译作为实现策略之一(其他方法是具有JIT的VM,使用JVM等)。他们的编译C版本平均运行速度比CPython慢​​,但对于某些程序,运行速度要快得多。

Shedskin是一个实验性的Python到C ++编译器。

Pyrex是专门为编写Python扩展模块而设计的语言。它旨在弥合Python的精美,高级,易于使用的世界与C的凌乱,低级的世界之间的鸿沟。

就像@Greg Hewgill所说的那样,有很多理由说明为什么这种情况并非总是可能的。但是,某些类型的代码(例如非常算法的代码)可以变成"真实的"机器代码。

有几种选择:

  • 使用Psyco,它可以动态发出机器代码。不过,我们应该仔细选择要转换的方法/函数。
  • 使用Cython,这是一种类似Python的语言,已被编译为Python C扩展
  • 并非所有扩展名都存在

之后,我们可以使用现有的软件包之一(freeze,Py2exe,PyInstaller)将所有内容放入一个二进制文件中。

总而言之:问题没有一般性的答案。如果我们具有对性能至关重要的Python代码,请尝试使用尽可能多的内置功能(或者询问"如何使我的Python代码更快"问题)。如果这样做没有帮助,请尝试识别代码并将其移植到C(或者Cython)并使用扩展名。

Pyrex是可编译为C的Python语言的子集,由最初为Python建立列表理解的人完成。它主要是为建筑包装纸而开发的,但可以在更一般的环境中使用。 Cython是派热克斯(pyrex)维护得更积极的分支。

答案是"是的,有可能"。我们可以使用Python代码,并尝试使用CPython API将其编译为等效的C代码。实际上,过去曾经有一个Python2C项目做到了这一点,但是我已经很多年没有听说过了(在Python 1.5天内是我最后一次看到它的时候。)

我们可以尝试将Python代码尽可能多地转换为本机C,然后在需要实际的Python功能时退回到CPython API。最近一两个月,我自己一直在想这个主意。但是,这需要大量的工作,并且大量的Python功能很难转换为C:嵌套函数,生成器,除带有简单方法的简单类之外的任何东西,涉及从模块外部修改模块全局变量的任何东西,等等。 , 等等。