Python 3 解释器是否具有 JIT 特性?

94
我发现当我向Python询问更多内容时,Python并没有以100%的机器资源使用率来运行,速度也不是非常快。如果与许多其他解释性语言相比,它是快速的,但与编译型语言相比,差异是显著的。在Python 3中使用即时编译器(JIT)是否有可能加速处理速度?
通常情况下,即时编译器是唯一可以提高解释性语言性能的方法,因此我正在参考这个方案,如果有其他可用解决方案,我会很乐意接受新答案。

5
PyPy拥有JIT: http://doc.pypy.org/en/latest/jit/index.html。 - rubik
@rubik 谢谢,但我在寻找Python 3的解决方案,而不是Python 2,并且是官方解释器,不是其他解释器。 - guz
1
尽管pypy尚不支持Python 3,但根据你的需求,有各种提高性能的方法可以采用 - 例如使用更好的算法,使用multiprocssingthreading 模块进行并行化,或者使用C语言编写扩展(可以借助 cython 或类似软件来简化)。 - James
大多数 Python 的实现并非解释执行,而是编译成字节码。 - Russell Borogove
3
@rubik,很好的建议。我会在你的列表中添加一项:“使用现有的扩展库(如NumPy)”。 - jimhark
7个回答

94
首先,Python 3(.x) 是一种语言,可以有任意数量的实现。好吧,直到今天除了CPython之外,没有任何实现实际上实现了这些版本的语言。但这将会改变(PyPy正在追赶)。
回答你想问的问题:CPython,无论是3.x还是其他版本,都不会、从未并且很可能永远不会包含JIT编译器。其他一些Python实现(PyPy本地支持,Jython和IronPython通过重用虚拟机构建的JIT编译器)确实具有JIT编译器。当它们添加对Python 3的支持时,它们的JIT编译器也不会停止工作。
但是在这里,我也要解决一个误解:
通常情况下,只有JIT编译器才能提高解释语言的性能
这是不正确的。JIT编译器,在其最基本的形式中,仅仅消除了解释器的开销,这占据了你看到的一些减速的原因,但不占大多数。一个好的JIT编译器还执行了大量的优化,这些优化消除了实现许多Python特性所需的开销(通过检测允许更有效的实现的特殊情况),突出的例子包括动态类型、多态和各种内省特性。

仅仅实现编译器是不够的。你需要非常聪明的优化,其中大部分只在非常特定的情况下和有限的时间窗口内有效。JIT编译器在这方面很容易,因为它们可以在运行时生成专门的代码(这是它们的全部目的),可以通过观察程序运行来更轻松(更准确地)分析程序,并且在优化失效时可以撤消优化。与预先编译的编译器不同,它们还可以与解释器交互,并经常这样做,因为这是一个明智的设计决策。我想这就是为什么人们将它们与解释器联系起来的原因,尽管它们可以独立存在。

除了优化解释器代码本身之外,还有其他方法可以使Python实现更快,例如HotPy(2)项目。但是,这些方法目前仍处于研究或实验阶段,并且有待证明它们对真实代码的有效性(和成熟度)。

当然,一个特定程序的性能更多地取决于程序本身而不是语言实现。语言实现仅设置了一系列操作的速度上限。通常情况下,你可以通过避免不必要的工作来提高程序的性能,即通过优化程序。无论你是通过解释器、即时编译器还是静态编译器运行程序,这都是正确的。如果你想让某些东西运行得更快,不要费力去寻找更快的语言实现。有一些应用程序由于解释和动态性的开销而不可行,但它们并不像你想象的那样常见(通常通过调用机器代码编译的代码进行选择性解决)。

我听说Google有意为3.x版本推出的Python引入JIT以提高其速度,因此我一直在寻找答案。使用不同的解释器的问题在于你最终会拥有多个实现,而且许多提供内置Python控制台的应用程序只引用官方Python解释器。所以最终对于Python 3来说没有什么好的和准备好的东西吗? - guz
8
谷歌的Unladden Swallow项目早就被放弃,尽管他们的一些工作在CPython和其他地方得以延续,但他们的JIT编译器已经死亡(一开始就表现不佳)。总体而言,我认为拥有多个实现是一种优势,虽然关于嵌入的观点很好。 - user395760
Java的JIT不是为JVM编译吗?我猜Jython也会做同样的事情。如果是这样,我们不能说Python为自己的VM编译吗?“dis”模块可以显示实际运行的内容。 - Noctis Skytower
4
大多数JVM都包含一个JIT编译器,它将Java字节码编译成机器码(据我所知,Jython生成JVM字节码)。CPython和PyPy确实在运行之前将Python代码编译为他们自己的内部字节码。但这并不使它们成为通常意义上的JIT编译器(这包括编译到本机代码输出,并与运行时的其他部分紧密集成)。 - user395760
2
@delnan 感谢您的澄清!发现实际上有多个编译级别是很有趣的。源代码 -> 字节码 -> 本机代码,然后微处理器将其解释为微代码... - Noctis Skytower
2
我用Python实现了一个相对简单的Levenshtein距离修改。那个程序被频繁地调用,所以我重新用C语言实现,但仍使用了Python存储类型,没有进行任何优化。因此,代码基本相同,执行时间从5秒降至200毫秒。CPython很难在运行CPU密集型操作时表现良好。如果CPU和RAM导致执行时间过慢,则编译而不是解释总会导致大幅度的加速。JIT是一种在许多场景下提高性能而不损失程序员便利性的方法。 - Gellweiler

18

目前唯一支持JIT的Python实现是PyPy,PyPy同时支持Python 2和Python 3。


5
Python 3现在的支持已经更加完备,达到了Python 3.2的水平。 - naught101
现在 RustPython 解释器上有一个实验性的 JIT,可以在 https://github.com/RustPython/RustPython 上找到。 - Scott Driggers

12

1
据我所知,Numba并不是Python的实现,也从未打算成为Python的实现。相反,它显然是一种看起来类似Python但实际上与Python完全不同的语言的实现——为了性能而牺牲了许多语言特性。如果我错了,请纠正我。也许是PyPy开发人员洗脑了我,但我认为除了说明它与Python完全不同之外,这不应该与Python进行比较(甚至称之为Python)。 - user395760
@delnan:很有趣。为什么不叫它少功能的Python呢?我不太了解这个项目,但如果我理解正确的话,你只需要有一个Python文件,然后应用jit装饰器就可以了 :) 可能这太乐观和/或天真了。实际上,我甚至还没有尝试过,虽然我想... - rubik
因为“功能较少的Python”不是Python,它是一种非常不同的语言,也被接受为Python。是的,假设它可以正常工作太乐观了。除非Numba开发人员单枪匹马地完成了PyPy所做的事情,并在更短的时间内以更少的人力资源和更多的限制支持了Numba,否则Numba必然只支持Python的一个小子集。我会说最小限制是(隐式的,易于推断的)静态类型。如果他们也支持任意用户定义的对象,我会感到愉快的惊喜,但我怀疑这一点。 - user395760
@delnan:好的,你说服我了!以后我在回答中不会再称它为Python了!;) - rubik

8

谢谢,我只对官方的Python解释器版本3.x感兴趣,所以我会把这个视为“不行”。 - guz

4

这个问题最好由这个网站上一些出色的Python开发人员来回答。

不过我想评论一下:当讨论解释语言的速度时,我喜欢指向一个托管在此位置:计算机语言基准测试游戏的项目。

这是一个致力于运行基准测试的网站。有指定的任务要完成。任何人都可以用自己喜欢的语言提交解决方案,然后测试比较每个解决方案的运行时间。解决方案可以进行同行评审,经常会被其他人进一步改进,并且结果会与规范进行检查。从长远来看,这是比较不同语言的最公平的基准测试系统。

正如你可以从类似于这个的指示性摘要中看到的那样,编译语言相对于解释语言而言非常快。但是,差异可能不在于确切的编译类型,而在于Python(以及图表中比Python慢的其他语言)是完全动态的。对象可以即时修改。类型可以即时修改。因此,某些类型检查必须推迟到运行时,而不是编译时。

因此,虽然你可以争论编译器的好处,但你必须考虑到不同语言中的不同特性。这些特性可能会带来内在的代价。

最后,在谈论速度时:大多数情况下,导致问题的不是语言和语言的感知缓慢,而是糟糕的算法。我从来没有因为一种语言太慢而不得不切换语言:当我的代码存在速度问题时,我修复算法。然而,如果你的代码中有耗时的、计算密集型循环,重编译它们通常是值得的。一个著名的例子是用C编写的库,被脚本语言使用(Perl XS库,或例如numpy/scipy用于Python,lapack/blas是许多脚本语言可用绑定的库的示例)


是的,但如果我只是从source.py文件运行代码,我可能无法受益于这种动态性。而且在我从文件运行代码的确切时刻,您可以确定我的操作系统、平台和我的程序将要做什么,这些可能是有用的信息,可以像JIT示例中那样进行优化。 - guz
@igouy:感谢您指出。我已经澄清了我的回答。 - cfi
项目名称显示在每个页面的横幅和网络浏览器标题栏中,在网站上显示的段落说明为什么该项目至少5年没有被称为“shootout”或其他任何名称。 - igouy
你有点挑剔,但也许是正确的。已更改名称。请对批评者温柔些:服务器仍然被命名为shootout,而我比我愿意承认的年龄要大得多,并且已经习惯了这个名称多年。我相信更改名称只是文字游戏,因为最终上下文才是最重要的。如果人们以前不理解跨语言基准测试的优点和问题,现在他们也不会理解。我仍然进行了更正,因为我相信文字的魔力,而且我自己也是一个吹毛求疵的人 :-) 真的,感谢您努力进行更正。 - cfi
在谷歌搜索结果中浏览色情网站和大学集体谋杀事件,对我来说并不是一个明亮愉快的一天开始方式 - 因此,在弗吉尼亚理工大学事件之后,我改变了名称。 - igouy

2
如果你说的 JIT 是指将代码编译成字节码表示形式的即时编译器,那么它有这样的功能(自 2.2 版本开始)。如果你指的是将代码编译成机器码的 JIT,则没有。但编译成字节码可以大大提高性能。如果你想将代码编译成机器码,则需要使用 Pypy 实现。
注意:Pypy 不支持 Python 3.x 版本。

0
如果您正在寻找代码块的速度改进,那么您可能需要查看rpythonic,它使用pypy编译成C。它使用一个装饰器将其转换为Python的JIT。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接