PyPy——它怎么可能比CPython更快?
4 个回答
PyPy是用Python写的,但它有一个即时编译器,可以实时生成本地代码。
之所以选择在Python上实现PyPy,可能是因为Python本身就是一种非常高效的编程语言,尤其是因为这个即时编译器让Python的性能问题变得不那么重要。
“PyPy是用Python重新实现的Python”这个说法有点误导,虽然从技术上讲是对的。
PyPy主要有两个部分。
- 翻译框架
- 解释器
翻译框架其实是一个编译器。它把RPython代码编译成C代码(或者其他目标),并自动添加一些功能,比如垃圾回收和即时编译器(JIT)。不过,它不能处理任意的Python代码,只能处理RPython。
RPython是普通Python的一个子集;所有RPython代码都是Python代码,但反过来就不成立。RPython没有正式的定义,因为它基本上就是“可以被PyPy的翻译框架翻译的Python子集”。为了能被翻译,RPython代码必须是静态类型的(类型是推断出来的,你不需要声明,但每个变量仍然只能有一种类型),而且你不能在运行时声明或修改函数/类。
解释器就是用RPython写的普通Python解释器。
因为RPython代码是普通Python代码,所以你可以在任何Python解释器上运行它。但PyPy的速度优势并不是通过这种方式获得的;这只是为了快速测试,因为翻译解释器需要很长的时间。
理解了这些,就会明白关于PyPyPy或PyPyPyPy的猜测其实没有意义。你有一个用RPython写的解释器。你把它翻译成C代码,这样就能快速执行Python。到此为止,过程就结束了;没有更多的RPython可以通过再次处理来加速。
所以“PyPy怎么可能比CPython快”这个问题也变得很明显。PyPy有更好的实现,包括一个JIT编译器(我认为没有JIT编译器时,它通常不那么快,这意味着PyPy只有在程序适合JIT编译时才会更快)。CPython从来不是为了成为一个高度优化的Python语言实现而设计的(尽管他们确实努力让它成为一个高度优化的实现,如果你了解这两者的区别)。
PyPy项目真正创新的地方在于,他们并不是手动编写复杂的垃圾回收方案或JIT编译器。他们相对简单地用RPython写了解释器,尽管RPython比Python低级,但它仍然是一个面向对象的、带垃圾回收的语言,比C高级得多。然后翻译框架自动添加垃圾回收和JIT等功能。因此,翻译框架是一个巨大的工程,但它对PyPy的Python解释器的实现变化适用,使得在改进性能时有更多的实验自由(而不必担心引入垃圾回收错误或更新JIT编译器以应对变化)。这也意味着,当他们开始实现Python3解释器时,它会自动获得相同的好处。还有其他用PyPy框架编写的解释器(这些解释器在不同的完善阶段)。所有使用PyPy框架的解释器都自动支持框架支持的所有平台。
所以,PyPy项目的真正好处在于尽可能地将实现一个高效的、平台无关的动态语言解释器的各个部分分开。然后在一个地方提出一个好的实现,可以在多个解释器中重复使用。这不是像“我的Python程序现在运行得更快”那样的直接好处,但对未来来说是个很好的前景。
而且它可以让你的Python程序运行得更快(也许)。
问1:这怎么可能呢?
手动管理内存(CPython就是这样做的,通过计数来管理)在某些情况下可能比自动管理要慢。
CPython解释器的实现限制了某些优化,而这些优化是PyPy可以做到的(比如更细粒度的锁)。
正如Marcelo提到的,JIT(即时编译)。能够在运行时确认一个对象的类型,可以省去多次解引用指针的麻烦,从而更快地找到你想调用的方法。
问2:实现PyPy用的是哪个Python版本?
PyPy解释器是用RPython实现的,RPython是Python的一种静态类型子集(指的是语言本身,而不是CPython解释器)。- 详细信息请参考https://pypy.readthedocs.org/en/latest/architecture.html。
问3:PyPyPy或PyPyPyPy有可能超越它们的表现吗?
这取决于这些假设的解释器的实现。如果其中一个解释器,比如说,直接对源代码进行分析,然后将其转换为特定目标的紧凑汇编代码,经过一段时间的运行,我想它会比CPython快很多。
更新:最近,在一个精心设计的例子中,PyPy的表现超过了用gcc -O3
编译的类似C程序。这是一个特定的案例,但展示了一些想法。
问4:为什么会有人尝试这样的事情?
来自官方网站的说明。https://pypy.readthedocs.org/en/latest/architecture.html#mission-statement
我们的目标是提供:
一个通用的翻译和支持框架,用于生成动态语言的实现,强调语言规范和实现方面的清晰分离。我们称之为
RPython工具链
。一个合规、灵活且快速的Python语言实现,利用上述工具链来启用新的高级特性,而无需编码底层细节。
通过这种方式分离关注点,我们的Python实现——以及其他动态语言——能够自动生成任何动态语言的即时编译器。这也允许在实现决策上进行灵活组合,包括许多历史上用户无法控制的因素,比如目标平台、内存和线程模型、垃圾回收策略,以及应用的优化,包括是否使用JIT。
gcc编译器是用C实现的,Haskell编译器GHC是用Haskell编写的。你有什么理由认为Python解释器/编译器不能用Python编写吗?