如果PyPy快6.3倍,为什么我不应该在CPython上使用PyPy?


683

我已经听到很多有关PyPy项目的信息。他们声称它比其站点上的CPython解释器快6.3倍。

每当我们谈论诸如Python之类的动态语言时,速度都是头等大事。为了解决这个问题,他们说PyPy快6.3倍。

第二个问题是并行性,臭名昭著的Global Interpreter Lock(GIL)。为此,PyPy表示可以提供无GIL的Python

如果PyPy可以解决这些巨大的挑战,那么它的哪些弱点正在阻碍广泛采用?也就是说,是什么原因导致我这样的人,一个典型的Python开发,切换到PyPy 现在


30
清除评论,因为大多数是应该在答案中充实(在某些情况下是),或者根本不应该说的东西。还进行了编辑,以解决有关此问题的主观性的一些担忧。请尝试使用事实来回答,并在可能的情况下用源备份断言!
Shog9 2013年

3
我经常使用Pypy。它往往工作得很好。但是,虽然Pypy对于许多CPU繁重的工作负载而言要快很多,但对于我投入的I / O繁重的工作负载却实际上要慢一些。例如,我编写了一个称为backshift的重复数据消除备份程序。对于进行大量文件分块的初始备份,pypy很棒。但是对于以后的备份(大多只是更新时间戳),CPython更快。
dstromberg

Answers:


655

注意: PyPy现在比2013年提出这个问题时更加成熟,并且得到了更好的支持。避免从过时的信息中得出结论。


  1. 正如其他人很快提到的,PyPy 对C扩展提供了长期的支持。它具有支持,但通常速度低于Python,并且充其量也只是个问题。因此,许多模块只需要 CPython。PyPy不支持numpy PyPy现在支持numpy。某些扩展仍然不受支持(Pandas,SciPy等),请在进行更改之前先查看支持的软件包的列表
  2. 目前,对Python 3的支持尚处于试验阶段。 刚刚达到稳定!自2014年6月20日起,PyPy3 2.3.1-Fulcrum退出了
  3. PyPy有时并不真正更快“脚本”,其中有很多人使用Python进行。这些是运行时间短的程序,它们执行简单和小的操作。由于PyPy是JIT编译器,因此其主要优点来自运行时间长和简单的类型(例如数字)。坦率地说,与CPython相比,PyPy的JIT之前速度非常差
  4. 惯性。迁移到PyPy通常需要重新配置工具,对于某些人和组织而言,这简直就是太多的工作。

我会说,这些是影响我的主要原因。


14
很高兴您提到了重新设计。例如,我的虚拟主机可以在Python 2.4和2.5之间进行选择。我附近的“娱乐软件的主要生产商”正在使用2.6,没有计划立即升级。有时,甚至发现转换成本可能是一项重大而昂贵的工作。
Mike Housky 2013年

19
PyPy“与C一样快”更多地是关于通用C,而不是高度优化的用于数字的多线程缓存感知C库。对于数字,Python仅用于传递指向大数组的指针。因此,PyPy的速度“与C一样快”意味着“您的指针+元数据的移动速度与C一样快”。没有大碍。那么,为什么还要打扰Python呢?去看看cblas和lapacke中的函数签名。
cjordan1

12
@ cjordan1:我不明白你在说什么。高级别的numpy构造np.sum(M[1:2*n**2:2, :2*n**2] * M[:2*n**2:2, :2*n**2].conjugate(), axis=1)在Python中具有极高的表现力(?),这使Python非常适合科学界。此外,在Python中执行非密集型部分并为较小的密集型循环使用C语言是一种常见且可用的策略。
Veedrac

26
@Vedrac是我的意思。就像在“看看cblas和lapacke中的函数签名”中一样,因为它们太长且难以使用,您将立即理解为什么我们使用Python来传递指针和元数据。
cjordan1 2013年

5
@ tommy.carstensen这并不是深入的好地方,但是我会尝试的。1.当我写这篇文章时,这比现在要真实得多。2. “脚本”经常是大量的IO。PyPy的IO仍然通常比CPython的IO慢-过去要慢得多。3.在处理字符串时,PyPy过去比CPython慢​​-现在,它通常更好,很少恶化。4.许多“脚本”只是胶合代码-在这种情况下,提高解释器的速度不会改善整体运行时间。5. PyPy的预热时间过去更长-运行时间短的脚本很少能产生大量热代码。
Veedrac

104

该网站也没有权利要求PyPy比CPython的快6.3倍。报价:

所有基准的几何平均值比CPython快0.16或6.3倍

这与您所做的一揽子声明完全不同,当您了解差异时,您将至少了解一组不能仅仅说“使用PyPy”的原因。听起来好像我很挑剔,但是了解为什么这两个陈述完全不同是至关重要的。

分解:

  • 他们所做的陈述仅适用于他们所使用的基准。它完全没有说明您的程序(除非您的程序与其基准之一完全相同)。

  • 该声明大约是一组基准的平均值。没有人声称运行PyPy甚至可以为他们测试过的程序带来6.3倍的改进。

  • 没有人声称PyPy甚至可以运行CPython运行的所有程序,更不用说更快了。


15
当然,没有人声称PyPy将更快地运行所有Python代码。但是,如果您使用所有纯Python应用程序,我敢打赌,它们中的绝大部分将在PyPy上比在CPython上运行得快得多(> 3倍)。
罗伯特·扎伦巴

18
前两个要点都没有道理。你怎么能说基准测试说“绝对没有关于你的程序”。显然,基准测试并不是所有实际应用程序的完美指标,但它们绝对可以用作指标。同样,我也不理解您对它们报告一组基准测试的平均值有何误解。他们很清楚地说这是一个平均值。如果程序员不理解平均水平,那么他们比语言性能要严重得多。
肖恩·杰弗里·皮茨

6
@SeanGeoffreyPietz-我并不是说PyPy的网站有任何误导性-他们准确地展示了他们的结果。但是最初的问题对它们的报价有误,并表明作者不理解“平均”一词的重要性。许多单独的基准测试速度都不快6.3倍。而且,如果您使用不同类型的平均值,您将获得不同的值,因此“ 6.3倍速”是“几何平均值快6.3倍”的充分总结。“ A组的速度比B组的速度快Z倍”,这样的含义太含糊了。
spookylukey

6
-1:@spookylukey您似乎暗示基准套件存在偏见,而没有提供支持该主张的证据。批评应始终以证据为后盾!
Evgeni Sergeev 2014年

5
@EvgeniSergeev-不,我是说所有基准都存在偏见!当然,不一定是故意的。可能有用的程序的空间是无限的,并且难以置信地是多种多样的,并且一组基准仅能衡量这些基准的性能。问“ PyPy比CPython快多少?” 就像问“弗雷德要比乔快多少?”,这似乎是OP想要知道的。
spookylukey

74

由于pypy并非100%兼容,因此需要8 gig的ram进行编译,这是一个不断变化的目标,并且处于高度试验阶段,而cpython是稳定的,这是模块构建器默认的目标,长达20年(包括无法在pypy上运行的c扩展名) ),并且已经广泛部署。

Pypy可能永远不会成为参考实现,但是它是一个很好的工具。


2
根据pypy.org/download.html,PyPy需要4 GB的RAM进行编译(在64位系统上),而不是8。并且该页面上有一个选项可以在3 GB以下进行编译。
knite

4
@knite 1:这是2015年的新功能,该文档历来读取8 GB。2:在2015年的实践中,您仍然至少需要8位,其中6-7位免费。
Tritium21

4
如果使用内部版本或发行版,则编译所需的内存要求并不重要。至于“不断变化的目标和高度实验性的”,您能否举几个例子,看看有什么坏处?再者,如果人们使用的是发布版本而不是夜间版本或源代码,那么他们对功能是否有合理的期望?
smci

@smci这是一个基于古老数据的古老问题,带有古老答案。考虑这个问题和每个答案对于4年前的pypy状态都是历史性的。
Tritium17年

1
@ Tritium21:我只对当前答案感兴趣。它是什么?您可能希望编辑答案以说“截至2013年,比较pypy与2.x版本的Python是...”而且,如果问题中的“ 6.3x几何平均”声明已过期(如在4/2017中,他们声称是7.5倍,但即使如此,也要取决于基准...),然后也需要进行编辑(版本号,最新数据等)。我认为基准套件不太相关,几乎没有人可以运行这些天来,以脚本语言在CPU上进行光线跟踪。我确实找到pybenchmarks.org
smci

36

第二个问题更容易回答:如果所有代码都是纯Python,则基本上可以使用PyPy替代。但是,许多广泛使用的库(包括一些标准库)都是用C编写的,并作为Python扩展进行编译。其中有些可以与PyPy一起使用,有些则不能。PyPy提供了与Python相同的“面向前”工具-也就是说,它是Python-,但是它的内在功能是不同的,因此与这些内在功能连接的工具将不起作用。

关于第一个问题,我想这有点像第一个Catch-22:PyPy一直在迅速发展,以提高速度并增强与其他代码的互操作性。这使其比官方更具实验性。

我认为,如果PyPy进入稳定状态,则有可能开始被更广泛地使用。我也认为Python摆脱C的支持是很棒的。但这不会一会儿发生。PyPy还没有达到临界质量的地方是几乎对自己有用的,足以做你想要的一切,这将激励人们以填补空白。


17
我不认为C是很快就会流行的语言(我愿意说,它不会在我们的一生中消失)。直到有另一种语言可以在任何地方运行,我们才有了C。(请注意,JVM是用C编写的。即使是java,“无处不在”的语言也需要C。其观点。
Tritium13年

7
@ Tritium21:是的,我只是在那里编辑。我对现有的C表示满意,但是我认为Python对C的依赖是非常有害的,而PyPy就是一个很好的例子,原因是:现在我们有机会获得更快的Python,但是多年以来对C的依赖使我们为难对于Python来说,站在自己的两只脚上会更好。如果Python本身是用C编写的,这还可以,但是问题是存在一种扩展机制,该机制鼓励人们以依赖C的方式扩展
Python。– BrenBarn

4
这方面的双刃剑-使python如此流行的部分原因是它具有扩展其他应用程序和被其他应用程序扩展的能力。如果您将其删除,我认为我们不会在谈论python。
Tritium13年

10
@BrenBarn断言Python对C的依赖是有害的。如果没有Python的C-API,Python在其成年时期(90年代后期)获得的大多数真正强大的库和出色的互操作就不可能实现,包括整个数字/科学生态系统和GUI界面。在做出此类笼统的声明之前,请环顾四周以了解Python使用的整个领域。
彼得·王

4
@PeterWang所有这些库都可以用Python编写,但是它们的速度不如它们快。BrenBarn的意思是,现在我们有机会使python足够快,以便可以使用python编写这些库,但我们拒绝抓住这个机会,因为这样做意味着丧失使用C库的能力。我相信这是他的意思由有害的,不就是C库的存在是一件坏事,但是,为了使快速库的唯一方法是使用C.
维吉

14

我对此主题做了一个小型基准测试。尽管许多其他发布者在兼容性方面都提出了很好的观点,但我的经验是,PyPy仅仅移动一些位并没有那么快。对于Python的许多用途,它实际上仅存在于在两个或多个服务之间转换位。例如,很少有Web应用程序对数据集执行CPU密集型分析。相反,它们从客户端获取一些字节,将其存储在某种数据库中,然后再将其返回给其他客户端。有时,数据格式会更改。

BDFL和CPython开发人员是一群非常聪明的人,并设法帮助CPython在这种情况下表现出色。这是一个无耻的博客插件:http : //www.hydrogen18.com/blog/unpickling-buffers.html。我正在使用Stackless,它是从CPython派生的,并保留了完整的C模块接口。在那种情况下,我发现使用PyPy没有任何优势。


1
PyPy有许多精心运行的基准测试(不幸的是,与CPython不同,CPython目前还没有面向用户的基准测试套件)。当然,对于网络流量,PyPy无法神奇地使任何事情变得更快。
朱利安

1
朱利安(Julian),值得注意的是,多年来,PyPy一直致力于改善该特定基准套件的运行时间。在某种程度上,它们似乎在优化方面无法适应这套基准测试,并且根据我的经验,除了纯数值计算(无论如何在Fortran或C99中都更好)之外,我从来没有让PyPy变得更好比CPython快2倍以上。
Alex Rubinsteyn

9
@AlexRubinsteyn但是,从事PyPy的人们通常认为,如果您发现PyPy比CPython慢​​的情况,并且可以将其转变为合理的基准,则很有可能将其添加到套件中。
gsnedders

1
我检查了您的博客。在您的结果中,(pickle,StringIO)的普通python对显示pypy比cpython快约6.8倍。我认为这是一个有用的结果。在结论中,您指出(正确)了pypy代码(纯python!)比C代码(cPickle,cStringIO)慢,而不是cpython代码。
Caleb Hattingh 2014年

1
@gsnedders我已经提供了基于基准rinohtype多个 场合。他们尚未将其添加到套件中。
Brecht Machiels '17

12

问:如果与CPython相比,PyPy可以解决这些巨大的挑战(速度,内存消耗,并行性),那么它的哪些弱点在阻止更广泛的采用?

答:首先,很少有证据表明PyPy团队可以解决问题的速度一般。长期证据表明,PyPy运行某些Python代码要比CPython慢​​,而且这一缺点似乎深深地植根于PyPy。

其次,在相当多的情况下,当前版本的PyPy消耗的内存比CPython多得多。因此,PyPy尚未解决内存消耗问题。

无论PyPy解决所提到的巨大挑战,并在一般更快,较少的内存饿了,和更友好的并行与CPython是一个悬而未决的问题无法在短期内得到解决。有人押注,PyPy将永远无法提供一种通用解决方案,使它在所有情况下均能统治CPython 2.7和3.3。

如果PyPy总体上要比CPython更好,这是值得怀疑的,那么影响其广泛采用的主要弱点将是与CPython的兼容性。还存在一些问题,例如CPython可在更广泛的CPU和OS上运行,但是与PyPy的性能和CPython兼容性目标相比,这些问题的重要性要小得多。


问:为什么现在不能放弃用PyPy替换CPython?

答:PyPy并非100%与CPython兼容,因为它没有在后台模拟CPython。有些程序可能仍依赖于PyPy中缺少的CPython的独特功能,例如C绑定,Python对象和方法的C实现,或CPython垃圾收集器的增量性质。


该答案没有引用任何基准或提供参考。
qwr

7

CPython具有引用计数和垃圾收集,PyPy仅具有垃圾收集。

因此,对象倾向于更早地删除,并__del__在CPython中以更可预测的方式调用。一些软件依赖于这种行为,因此它们还没有准备好迁移到PyPy。

某些其他软件可同时使用这两种软件,但CPython使用较少的内存,因为较早时释放了未使用的对象。(我没有任何度量来表明这有多重要,还有哪些其他实现细节会影响内存使用。)


17
应该强调的__del__是,即使在CPython中,过早或根本不被调用也是错误的。正如您所说,它通常有效,有人认为这是可以保证的。如果引用对象的任何内容都在引用周期中被捕获(这很容易-您是否知道以某种非人为的方式检查当前异常会创建一个引用周期?)终结处理将无限期延迟,直到下一个周期GC (可能永远不会)。如果对象是本身的引用周期的一部分,__del__将不调用在所有(现有到Python 3.4)。

3
在CPython中,每个对象的开销更高,一旦开始创建大量对象,这就很重要。我相信PyPy在默认情况下做相当于插槽的事情。

4

对于许多项目,在速度方面,不同的python之间实际上有0%的差异。那就是那些受工程时间支配并且所有python都具有相同数量的库支持的库。


1
如果您的项目是如此简单,那么显然没关系,但是任何一种语言的实现都可以这么说:如果您所做的只是通过性能相对较高的ABI集合其他库的功能,那么这一切都是无关紧要的。

1
它与简单没有任何关系。在工程设计中,反馈回路很重要。有时比运行时间重要得多。
Stephan Eggermont 2014年

1
好吧,您的发言含糊不清(工程时间不涉及正在设计的内容,约束条件等;反馈循环不涉及被反馈给谁的内容,等等),所以我要退出对话,而不是交易隐秘的引用。

这里没什么模糊的。看一下OODA循环或PDCA。
Stephan Eggermont 2014年

3
@user好吧,任何使用一个月编写一个分钟并运行一分钟的运行一次项目,即使PyPy快一千倍,使用PyPy也会使总体速度提高0.0%(1个月+1分钟vs 1个月)。斯蒂芬并非声称所有项目的速度都将提高0%。
gmatht

4

简单地说:PyPy提供了CPython所缺乏的速度,但却牺牲了它的兼容性。但是,大多数人选择Python是因为它具有灵活性和“含电池”功能(高兼容性),而不是因为它的速度(尽管它仍然是首选)。


16
“含电池”是指大型标准库 AFAIK
tshepang

4

我发现了一些例子,其中PyPy比Python慢​​。但是:仅在Windows上。

C:\Users\User>python -m timeit -n10 -s"from sympy import isprime" "isprime(2**521-1);isprime(2**1279-1)"
10 loops, best of 3: 294 msec per loop

C:\Users\User>pypy -m timeit -n10 -s"from sympy import isprime" "isprime(2**521-1);isprime(2**1279-1)"
10 loops, best of 3: 1.33 sec per loop

因此,如果您想到的是PyPy,请忘记Windows。在Linux上,您可以实现出色的加速。示例(列出1到1,000,000之间的所有素数):

from sympy import sieve
primes = list(sieve.primerange(1, 10**6))

PyPy的运行速度比Python快10(!)倍。但不在Windows上。那里只有3倍的速度。


有趣!一些更多的比较和数字会很棒。
ben26941'December

1

PyPy已经支持Python 3一段时间了,但是根据Anthony Shaw在2018年4月2日发布的HackerNoon帖子中所述,PyPy3仍然比PyPy(Python 2)慢几倍。

对于许多科学计算,尤其是矩阵计算,numpy是更好的选择(请参阅FAQ:我应该安装numpy还是numpypy?)。

Pypy不支持gmpy2。您可以改用gmpy_cffi, 尽管我尚未测试过它的速度,并且该项目在2014年发布了一个版本。

对于Project Euler问题,我经常使用PyPy,对于简单的数值计算通常from __future__ import division足以满足我的目的,但是截至2018年,Python 3支持仍在开发中,最好的选择是在64位Linux上。Windows PyPy3.5 v6.0(截至2018年12月)为最新版本。


0

支持的Python版本

引用PythonZen

可读性很重要。

例如,Python 3.7引入了数据类,Python 3.8引入了fstring =

Python 3.7和Python 3.8中可能还有其他更重要的功能。关键是PyPy目前不支持Python 3.7或Python 3.8。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.