为什么Python程序通常比C或C ++编写的等效程序慢?


72

为什么Python平均看来比C / C ++慢?我学习Python是我的第一门编程语言,但是我只是从C入手,已经感觉到明显的不同。


14
您是否知道Python被解释了?
S.Lott

9
@ kaizer.se-然后我们还需要说其他明显的事实,我们不使用编程语言,而使用编程语言实现;等等等等
igouy

6
@ kaizer.se:是的,我们知道,我们知道。但是,只需考虑在避免像您这样的评论的同时编写代码会很尴尬。“为什么Python代码(与任何通用解释器一起运行)这么慢?”
卡斯卡贝尔

6
经过大量讨论,这个问题有了第二次机会。我已经编辑了音调以防止其(重新)关闭和(重新)删除。令我惊讶的是,这个问题的1000名观众中,没有一个人投票赞成这个问题或答案,他们中的许多人都赞成关闭问题的原因或采取行动解决该问题的论调。
ire_and_curses 2010年

Answers:


87

Python是比C更高级的语言,这意味着它从您那里抽象出计算机的详细信息-内存管理,指针等,并允许您以更接近人类思维的方式编写程序。

的确,如果仅衡量执行时间,C代码的运行速度通常比Python代码快10至100倍。但是,如果还包括开发时间,Python通常会胜过C。对于许多项目,开发时间比运行时性能更为重要。较长的开发时间直接转化为额外的成本,较少的功能和较慢的上市时间。

在内部,Python代码执行速度较慢的原因是因为代码是在运行时解释的,而不是在编译时编译为本机代码。

其他解释语言(例如Java字节码和.NET字节码)的运行速度比Python快,因为标准发行版包括JIT编译器,可在运行时将字节码编译为本地代码。CPython还没有JIT编译器的原因是因为Python的动态特性使其难以编写。有工作进展情况写一个更快的Python运行,所以你应该期望的性能差距在今后可以减少,但它可能会需要一段时间Python标准版包括一个强大的JIT编译器前。


43
讲究技巧:Python通常不会在编译时编译为本机代码。仍然必须解释Python字节码。
Mark Byers 2010年

20
您还没有真正解释为什么Python实现往往会占用大量CPU。您可以对以上所有内容进行抽象处理,而不会在运行时产生太多的成本。Python的极端动态特性是它消耗了所有CPU:所有这些属性查找/方法分派加起来,甚至给JIT带来了相当艰辛的时间-并且Python目前通常不使用JIT使用。
SamB 2010年

@SamB:我现在添加了对其他交错语言的比较,以解决您的问题。我写的有关摘要的部分不是要解释为什么Python运行速度较慢,而是要解释为什么它可以更快地编程。
Mark Byers 2010年

2
回想起来,我认为有必要注意全局解释器锁以及Python中所有对象都是堆分配对象的方式,甚至是简单的整数。除了更高级的抽象之外,这些类型的事情无需深入研究具体的实现细节,就可能严重影响性能。话虽如此,我仍然认为大多数应用程序应该主要以脚本语言(例如Python)编写。正如Knuth所说的过早优化,实际上大多数应用程序中只有一小部分对性能至关重要。
stinky472

+1 [老实说,这就是为什么我要学习python来加快我的生产软件的速度,在这里老板需要加快开发速度]-“的确,如果仅衡量执行力,C代码的运行速度通常比Python代码快10至100倍时间。但是,如果还包括开发时间,Python通常会胜过C。对于许多项目,开发时间比运行时性能更为关键。更长的开发时间直接转化为额外的成本,更少的功能和更慢的上市时间。”

48

CPython特别慢,因为它没有即时优化器(因为它是参考实现,在某些情况下会选择简单性而不是性能)。Unladen Swallow是一个将LLVM支持的JIT添加到CPython中的项目,并实现了巨大的加速。Jython和IronPython可能比CPython快得多,并且它们由高度优化的虚拟机(JVM和.NET CLR)支持。

但是,可以说使Python变慢的一件事是它是动态类型的,并且每次属性访问都有大量查找。

例如,调用f一个对象A将导致可能的查找__dict__,调用 __getattr__等,然后最终调用__call__可调用对象f

关于动态类型,如果您知道要处理的数据类型,则可以进行许多优化。例如,在Java或C语言中,如果您有一个要求和的整数数组,则最终的汇编代码可以很简单,只需在索引处获取值,然后i将其添加到accumulator,然后递增即可。i

在Python中,很难使代码达到最佳状态。假设您有一个包含int的列表子类对象。在添加任何东西之前,Python必须先调用list.__getitem__(i),然后通过调用将其添加到“累加器”中accumulator.__add__(n),然后重复。由于其他线程可能已更改(例如,__getitem__在调用add或getitem之间,方法,列表实例的dict或类的dict。即使在本地名称空间中找到累加器和列表(以及您正在使用的任何变量),也会导致dict查找。使用任何用户定义的对象时,也会产生相同的开销,尽管对于某些内置类型,它有所减轻。

还值得注意的是,原始类型(如bigint(Python 3中为int,Python 2.x中为long),列表,集合,字典等)是人们在Python中使用很多的原始类型。这些对象上有许多内置操作,它们已经充分优化。例如,对于上面的示例,您只需调用即可,sum(list)而不使用累加器和索引。坚持这些,并使用int / float / complex进行一些数字运算,通常不会出现速度问题,如果这样做,可能会有一个时间紧迫的小单元(例如SHA2摘要功能)可以只需移至C(或Jython中的Java代码)即可。事实是,当您编码C或C ++时,您将浪费很多时间时间来完成您可以在几秒钟/几行Python代码中完成的工作。我要说的是,权衡总是值得的,除非您正在做诸如嵌入式或实时编程之类的事情而负担不起。


目前,Unladen Swallow是否会使用更多的内存?2009年第2季度[ code.google.com/p/unladen-swallow/wiki/Release2009Q2]结果说,内存增加了10倍,而2009年第3季度[ code.google.com/p/unladen-swallow/wiki/Release2009Q3]说他们做到了下降了930%(不确定如何解释该数字)。听起来内存不足是一个目标,但尚未实现。
布伦丹·朗

h,我写的那句话甚至都没有道理。
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 2010年

“然而,可以说使Python变慢的一件事是它是动态类型的,并且每次属性访问都有大量查找。” 实际上,这是PyPy中的JIT真正获胜的地方。JIT可以注意到您的代码在做一些不复杂的事情,并且可以优化一些简单的机器指令。因此,只要您在循环中做一些简单的事情,PyPy现在就会比CPython快得多。
steveha

19

编译与解释在这里并不重要:Python是经过编译的,对于任何不重要的程序,这仅占运行时成本的一小部分。

主要成本是:缺少与本机整数相对应的整数类型(使所有整数运算成本大大增加),缺少静态类型(这使方法的解析更加困难,并且意味着必须检查值的类型)在运行时),并且缺少取消装箱的值(这样可以减少内存使用量,并可以避免某种程度的间接访问)。

并非所有这些事情在Python中都是不可能实现的,或者不能使其变得更加高效,而是已经做出选择,是为了使程序员更方便,更灵活,以及在运行时速度上提高语言的清晰度。通过聪明的JIT编译可以克服其中的一些费用,但是Python提供的好处总是要付出一定的代价。


1
尽管要注意python并非总是编译的,但比公认的答案更好。确实是实现。根据我的经验,它经常被解释。
Triforcey

9

python和C之间的区别是解释型(字节码)和编译型(本机)语言之间的通常区别。就我个人而言,我并不真正认为python这么慢,它可以正常运行。当然,如果您尝试在其领域之外使用它,则速度会变慢。但是为此,您可以为python编写C扩展,它将对时间要求严格的算法放入本机代码中,从而使其速度更快。


2
一个/它/它。解释性还是编译性对优化性没有任何意义。JVM和C可以被解释或编译。两种情况下都可以应用不同的优化(自适应优化与编译时间+ LTO)
2010年

4
python编译为字节码,然后对其进行解释。它也可以编译为机器代码,因此从本质上讲,我们俩都不对。
Femaref 2010年

2
除了不完全正确之外,此答案还没有涉及真正的问题,@ Longpoke在其答案中对此进行了很好的解释。
SamB

4

除了已经发布的答案之外,还有一件事是python能够在运行时更改您在C中无法更改的内容。您可以随时向类添加成员函数。而且,python的动态特性使我们无法说出将什么类型的参数传递给函数,这反过来使优化工作更加困难。

RPython似乎是解决优化问题的一种方法。

尽管如此,对于数字压缩等而言,它的性能可能不会接近C。


为什么RPython不能合理执行?它不是直接转换为C吗?
SamB

显然,我并没有保持最新。甚至还有一个基准测试,RPython击败了gcc。未来已经来了:)
Mattias Nilsson 2010年

1
C没有类。您是说C ++吗?
罗曼·泰切

4

Python通常实现为脚本语言。这意味着它要经过一个解释器,这意味着它会即时将代码翻译成机器语言,而不是从一开始就将可执行文件全部翻译成机器语言。结果,除了执行代码外,它还必须支付翻译代码的费用。即使CPython即使编译为更接近机器语言的字节码也是如此,因此可以更快地翻译。Python还提供了一些非常有用的运行时功能,例如动态类型,但是即使没有最昂贵的运行时成本,即使在最有效的实现中,也通常无法实现这些功能。

如果您正在做非常耗费处理器的工作,例如编写着色器,那么Python的运行速度要比C ++慢200倍,这并不少见。如果您使用CPython,那么时间可以减少一半,但是仍然远远没有那么快。所有这些小东西都会带来一个代价。有很多基准可以证明这一点,这是一个特别好的基准。正如首页所承认的那样,基准是有缺陷的。它们都是由用户提交的,这些用户将尽力以自己选择的语言编写高效的代码,但这给了您一个很好的总体思路。

如果您担心效率问题,我建议您将两者混为一谈:那么,您可以同时兼顾两者。我主要是C ++程序员,但我认为很多人倾向于在C ++中编写平凡的高级代码,而这样做却很麻烦(编译时间只是一个示例)。将脚本语言与更接近金属的高效语言(如C / C ++)混合使用,实际上是平衡程序员效率(生产率)和处理效率的一种方法。


按照您的定义,Java也是脚本语言吗?两种语言都有在虚拟机中执行的某种字节代码。唯一的区别是,python可以在需要时即时编译,而Java通常不会这样做。
Mattias Nilsson 2010年

@Mattias:不;尽管您都正确地使用了字节码,但是Java在执行之前先将字节码编译为本地机器语言(预先或使用JIT编译器)。在某些情况下,Java字节码是某些微处理器的本机语言。另一方面,CPython是严格的字节码解释器。它可以即时完成所有翻译工作,这就是为什么它通常是其他Python实现速度的两倍,但仍不及Java速度那么快的原因。
stinky472 2010年

1
而且,CPython不会即时编译字节码,而是即时编译字节码。典型的实现将一遍又一遍地重新转换相同的字节码,就像您有一个循环一样。这就是为什么它仍然被认为是字节码解释器而不是编译器的原因。CPython确实将.py文件实时编译为.pyc(从Python转换为字节码),但这是完全不同的事情。pyc只是代码,对于解释器而言,它更易于阅读和翻译,但仍在解释中。Java方法更像是一种混合方法,这不仅是因为字节码,还在于它的用途。
stinky472 2010年

好的,我们正在探讨如何定义单词的问题。据此,java被解释为(或曾经被解释为)java.sun.com/docs/overviews/java/java-overview-1.html但是,是的,关于python代码没有被翻译成Java之类的本地机器代码,您有一点看法。当然,除非将psyco与CPython一起使用,否则它将生成机器代码。或者除非您运行解释的Java字节码,否则这也是可能的。当然,这意味着您不能在不指定程序执行方式的情况下就特定语言发表意见。
Mattias Nilsson 2010年

1
@igouy是的,但是如果我们学得那么烂,没有什么比Python慢​​C的了。如果有人投入足够的精力,他们也许能够提出性能相当的东西,但是通常不会发生。当您使用一种只能在运行时(例如自省)实现的机制动态键入的语言时,将会有运行时成本,甚至最好的实现者也无法完全忽略这一成本。也许有一天他们会找到一种革命性的新方法。
stinky472

4

将C / C ++与Python进行比较不是一个公平的比较。就像比较F1赛车和多功能卡车一样。

令人惊讶的是,与其他动态语言的同类相比,Python的速度有多快。尽管该方法通常被认为是有缺陷的,但请查看《计算机语言基准测试》,以了解类似算法上的相对语言速度。

与Perl,Ruby和C#的比较更加“公平”


3
我更喜欢使用兰博基尼超速行驶的隐喻,它可以工作5个街区(非内存安全语言),而街车则遵循速度限制(内存安全语言)。:)
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 2010年

C#是静态类型的btw,尽管它具有可选的动态类型。
L̲̳o̲̳̳n̲̳̳g̲̳̳p̲̳o̲̳̳k̲̳̳e̲̳̳ 2010年

5
C在我看来更像是一辆火箭车-如果您想直线行驶并且没有东西撞到附近,那就太好了,否则就不行了!
SamB

@drewk-您似乎甚至没有正确阅读该网站的标题。
igouy 2010年

@drewk-“通常被认为是有缺陷的”显示了这种影射的一些证据。
igouy 2010年

2

C和C ++编译为本地代码-即它们直接在CPU上运行。Python是一种解释型语言,这意味着您编写的Python代码必须经过很多很多抽象阶段才能成为可执行的机器代码。


在某些情况下,可以将Python编译为C ++,因此有时它的速度与本地代码一样快。
安德森·格林

-5

python被解释为不遵守语言,并且未与CPU硬件结合

但是我有一个解决方案可以将python增加为一种更快的编程语言

1.Use python3 for run and code python command like Ubuntu or any Linux distro use python3 main.py and update regularly your python so you python3 framework modules and libraries i will suggest use pip 3.

2.Use [Numba][1] python framework with JIT compiler this framework use for data visualization but you can use for any program this framework use GPU acceleration of your program.

3.Use [Profiler optimizing][1] so this use for see with function or syntax for bit longer or faster also have use full to change syntax as a faster for python its very god and work full so this give a with function or syntax using much more time execution of code.

4.Use multi threading so making multiprocessing of program for python so use CPU cores and threads so this make your code much more faster.

5.Using C,C#,C++ increasing python much more faster i think its called parallel programing use like a [cpython][1] .

6.Debug your code for test your code to make not bug in your code so then you will get little bit your code faster also have one more thing Application logging is for debugging code.

and them some low things that makes your code faster:

 1.Know the basic data structures for using good syntax use make best code.

 2.make a best code have Reduce memory footprinting.

 3.Use builtin functions and libraries.

 4.Move calculations outside the loop.

 5.keep your code base small.

所以使用这个东西可以更快地获取代码,是的,所以使用这个python并不是一种慢编程语言


1
欢迎来到SO。您关于加快Python速度的观点可能是正确的,但没有回答OP的问题:“为什么Python程序通常比C或C ++编写的等效程序慢?”
rtx13'4
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.