【问题标题】:Why are Python Programs often slower than the Equivalent Program Written in C or C++?为什么 Python 程序通常比用 C 或 C++ 编写的等效程序慢?
【发布时间】:2026-01-08 21:05:01
【问题描述】:

为什么平均而言 Python 似乎比 C/C++ 慢?我学习 Python 作为我的第一门编程语言,但我才刚刚开始使用 C,我已经感觉到我可以看到明显的不同。

【问题讨论】:

  • 你知道 Python 是被解释的吗?
  • @kaizer.se - 那么我们还需要说其他显而易见的事实,我们不使用编程语言,而是使用编程语言实现;等等等等
  • @kaizer.se:是的,我们知道,我们知道。但是想想在避免像你这样的 cmets 的同时写作是多么尴尬。 “为什么 Python 代码(使用任何通用解释器运行)这么慢?”
  • much discussion之后,这个问题得到了第二次机会。我已经编辑了音调以防止其(重新)关闭和(重新)删除。令我惊讶的是,这个问题的 1000 名观众(其中许多人投票赞成该问题或答案)中没有一个认为适合对关闭原因提出异议或采取行动解决问题的争论基调。

标签: c++ python c performance programming-languages


【解决方案1】:

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

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

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

其他解释型语言(例如 Java 字节码和 .NET 字节码)的运行速度比 Python 快,因为标准发行版包含一个 JIT compiler,它在运行时将字节码编译为本机代码。 CPython 没有 JIT 编译器的原因是因为 Python 的动态特性使得编写它变得困难。 progress 中有 work 用于编写更快的 Python 运行时,因此您应该期望将来会缩小性能差距,但标准 Python 发行版包含强大的 JIT 编译器可能还需要一段时间。

【讨论】:

  • 学究式:Python 通常不会在编译时编译为 native 代码。 Python 字节码仍然必须被解释。
  • 您还没有真正解释为什么 Python 实现往往如此占用 CPU。您可以抽象所有上述内容,而不会在运行时产生那么多成本;吃掉所有 CPU 的是 Python 的极端动态特性:所有这些属性查找/方法分派加起来,甚至给 JIT 带来相当困难的时间——而 Python 目前通常在没有 JIT 的情况下使用。
  • @SamB:我现在添加了与其他交互语言的比较来解决您的问题。我写的关于抽象的部分不是要解释为什么 Python 运行速度慢,而是要解释为什么它可以更快地编程。
  • 回想起来,我认为值得注意的是全局解释器锁以及 Python 中所有对象都是堆分配对象的方式,甚至是一个简单的整数。在不涉及具体的实现细节的情况下,这些类型的东西,除了更高级别的抽象之外,会对性能产生很大影响。也就是说,我仍然认为大多数应用程序应该主要使用 Python 等脚本语言编写。正如 Knuth 所说的过早优化,大多数应用程序中只有一小部分实际上对性能非常关键。
  • +1 [老实说,这就是我学习 python 的原因,以加快我的生产软件,而老板要求开发速度] - “确实,C 代码的运行速度通常比 C 代码快 10 到 100 倍Python 代码,如果你只测量执行时间。但是,如果你还包括开发时间,Python 通常会胜过 C。对于许多项目,开发时间远比运行时性能更重要。更长的开发时间直接转化为额外的成本,更少的功能和更慢的上市时间。”
【解决方案2】:

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

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

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

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

在 Python 中,很难使代码达到最佳状态。假设您有一个包含ints 的列表子类对象。在添加任何内容之前,Python 必须调用 list.__getitem__(i),然后通过调用 accumulator.__add__(n) 将其添加到“累加器”,然后重复。这里可能会发生大量替代查找,因为另一个线程可能已经改变了例如 __getitem__ 方法、列表实例的字典或类的字典,在调用 add 或 getitem 之间。即使在本地命名空间中找到累加器和列表(以及您正在使用的任何变量)也会导致 dict 查找。当使用任何用户定义的对象时,同样的开销也适用,尽管对于某些内置类型,它会有所减轻。

另外值得注意的是,原始类型,如 bigint(Python 3 中的 int,Python 2.x 中的 long)、list、set、dict 等,是人们在 Python 中经常使用的。这些对象上有大量的内置操作已经足够优化。例如,对于上面的示例,您只需调用 sum(list) 而不是使用累加器和索引。坚持这些,以及一些使用 int/float/complex 处理的数字,您通常不会遇到速度问题,如果您这样做,可能会有一个小的时间关键单元(例如 SHA2 摘要函数),您可以只需移出 C(或 Jython 中的 Java 代码)即可。事实是,当您编写 C 或 C++ 代码时,您将浪费 很多 时间来做一些可以在几秒钟/几行 Python 代码中完成的事情。我会说这种权衡总是值得的,除非您正在做嵌入式或实时编程之类的事情并且负担不起。

【讨论】:

  • Unladen Swallow 当前使用的内存不是稍微多一点吗? 2009 Q2 [code.google.com/p/unladen-swallow/wiki/Release2009Q2] 结果说内存增加了 10 倍,而 2009 Q3 [code.google.com/p/unladen-swallow/wiki/Release2009Q3] 说他们降低了 930%(不知道如何解释这个数字)。听起来降低内存是一个目标,但尚未实现。
  • 哎呀,我写的那句话根本没有意义。
  • “然而,可以说让 Python 变慢的一件事是它是动态类型的,并且每个属性访问都有大量的查找。”实际上,这正是 PyPy 中的 JIT 真正获胜的地方。 JIT 可以注意到您的代码正在做一些不复杂和简单的事情,并且可以针对一些简单的机器指令进行优化。因此,无论何时你在循环中做一些简单的事情,PyPy 现在都比 CPython 快得多。
【解决方案3】:

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

主要成本是:缺少对应于本机整数的整数类型(使所有整数操作变得更加昂贵),缺少静态类型(这使得方法的解析更加困难,并且意味着值的类型必须在运行时检查),并且缺少未装箱的值(这会减少内存使用,并且可以避免一定程度的间接)。

并不是说这些事情中的任何一项在 Python 中都不可能或无法提高效率,但我们做出的选择是有利于程序员的便利性和灵活性,以及​​语言的简洁性而不是运行时的速度。聪明的 JIT 编译可能会克服其中的一些成本,但 Python 提供的好处总是要付出一定的代价。

【讨论】:

  • 比公认的更好的答案,尽管重要的是要注意 python 并不总是被编译。这真的是执行。根据我的经验,它经常被解释。
【解决方案4】:

python 和 C 之间的区别通常是解释(字节码)语言和编译(本地)语言之间的区别。就个人而言,我并不认为 python 很慢,它管理得很好。如果你尝试在它的领域之外使用它,当然它会更慢。但为此,您可以为 python 编写 C 扩展,将时间关键型算法放入本机代码中,使其速度更快。

【讨论】:

  • s/它的/它的。就可优化性而言,解释与编译意味着 nothing。 JVM 和 C 可以被解释或编译。在任何一种情况下都可以应用不同的优化(自适应优化 vs 编译时间 + LTO)
  • python 编译成字节码,然后被解释。也可以编译成机器码,所以本质上,我们俩都不对。
  • 除了不完全正确之外,这个答案并没有谈到真正的问题,@Longpoke 在他的回答中解释得很好。
【解决方案5】:

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

如果您正在执行诸如编写着色器之类的处理器密集型工作,那么 Python 比 C++ 慢 200 倍左右的情况并不少见。如果你使用 CPython,时间可以减少一半,但仍然远没有那么快。所有这些小东西都是有代价的。有很多基准可以证明这一点,here's 是一个特别好的基准。正如头版所承认的那样,基准是有缺陷的。它们都是由尽力用他们选择的语言编写高效代码的用户提交的,但它为您提供了一个很好的总体思路。

如果您担心效率,我建议您尝试将两者混合在一起:这样您就可以两全其美。我主要是一名 C++ 程序员,但我认为很多人倾向于在 C++ 中编写太多平凡的高级代码,而这样做只是一件麻烦事(编译时间只是一个例子)。将脚本语言与更接近金属的高效语言(如 C/C++)混合使用确实是平衡程序员效率(生产力)和处理效率的方法。

【讨论】:

  • 按照您的定义,Java 也是一种脚本语言?两种语言都有某种在虚拟机中执行的字节码。唯一不同的是,python 在需要时即时编译,而 Java 通常不会这样做。
  • @Mattias:不;虽然您都使用字节码是正确的,但 Java 在执行之前将字节码编译为本机机器语言(提前或使用 JIT 编译器)。在某些情况下,Java 字节码是某些微处理器的本机机器语言。另一方面,CPython 是一个严格的字节码解释器。它即时完成所有翻译工作,这就是为什么它的速度通常是其他 Python 实现的两倍,但仍远不及 Java。
  • CPython 也不像动态解释字节码那样动态编译。典型的实现会一遍又一遍地重新翻译相同的字节码,就像你有一个循环一样。这就是为什么它仍然被认为是字节码解释器而不是编译器。 CPython 会即时编译 .py 文件到 .pyc(Python 到字节码),但这是完全不同的事情。 pyc 只是解释器更容易阅读和翻译的代码,但它仍然被解释。 Java 方法更像是一种混合方法,它不仅仅是因为字节码,还因为它用它做了什么。
  • 好的,我们正在讨论您如何定义单词的问题。据此,java 被解释(或被解释)java.sun.com/docs/overviews/java/java-overview-1.html 但是,你有一点关于 python 代码没有被翻译成像 Java 这样的本机机器代码。当然,除非您将 psyco 与生成机器代码的 CPython 一起使用。或者除非您运行 Java 字节码解释,这也是可能的。这当然意味着你不能在不指定程序如何执行的情况下谈论特定语言。
  • @igouy 是的,但如果我们变得如此迂腐,没有什么能让 Python 比 C 慢。如果有人在它上面付出足够的努力,他们可能会想出一些性能相当的东西,但这通常不会发生。当您拥有一种动态类型化的语言时,其机制只能在运行时实现,如内省,它会产生运行时成本,即使是最好的实现者也无法使这个成本完全可以忽略不计。也许有一天他们会找到一种革命性的新方法。
【解决方案6】:

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

令人惊讶的是,与其他动态语言的同类相比,Python 的速度有多快。虽然该方法通常被认为存在缺陷,但请查看 The Computer Language Benchmark Game 以了解类似算法的相对语言速度。

与 Perl、Ruby 和 C# 相比更“公平”

【讨论】:

  • 我更喜欢使用兰博基尼在 5 个街区外超速工作(非内存安全语言)与遵守速度限制的街车(内存安全语言)的比喻。 :)
  • C 对我来说更像是一辆火箭车——如果你想直线行驶并且附近没有任何东西可以撞到,那就太好了,否则就没有那么多了!
  • @igouy “The Great Computer Language Shootout”这个名字是 Debian 赞助之前的名字。您仍然可以使用该名称的 Google 和具有类似名称的其他名称找到它,例如 dada.perl.it/shootout/index.html
  • @igouy:“自 2001 年以来就没有更新”是什么意思?基准测试中的某些语言在 2001 年甚至不存在(C#、F#),英特尔四核参考机在 2001 年不存在。此站点定期更新。帮帮我:你的问题是什么?我没有对这种方法进行任何全面的谴责。它很有趣,很有用,但在某些方面存在缺陷。你有什么问题?查看 Pascal、C、Perl 和 Python 中的 Mandlebrot 基准测试。 C程序针对4核进行了高度优化; Perl 和 Pascal 根本没有优化。大惊喜:C 更快
  • @igouy:你说得对:那里的 Perl 代码已于 2010 年 5 月更新为多线程。可是等等!您声称the website that hasn't been updated since 2001,但您将我指向日期为 2010 年 5 月的页面。某些 Perl 作者必须比上一个 Perl 版本更快地成功生成所需的输出。哦,但是哎呀!您声称它不是基于输出!除了他们拥有的参考输出的差异之外,它基于什么?请,如果您在我所做的帖子上有 >> 建设性的
【解决方案7】:

除了已经发布的答案之外,还有一件事是 Python 能够在运行时更改事物,这是 C 等其他语言无法做到的。您可以随时将成员函数添加到类中。

此外,Python 的动态特性使得无法确定将传递给函数的参数类型,这反过来又使优化变得更加困难。

RPython 似乎是一种绕过优化问题的方法。

不过,它在数字运算等方面的性能可能不会接近 C 语言。

【讨论】:

  • 为什么 RPython 不能合理执行?它不是直接翻译成 C 吗?
  • 显然我没有让自己保持最新状态。甚至还有一个 RPython 击败 gcc 的基准。未来已经到来:)
  • C 没有类。你是说c++吗?
【解决方案8】:

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

【讨论】:

【解决方案9】:

Python 是一种高级编程语言。以下是 python 脚本的运行方式:

python源码先编译成Byte Code。是的,你明白我的意思了!尽管 Python 是一种解释型语言,但它首先会被编译成字节码。这个字节码然后由Python Virtual Machine(PVM) 解释和执行。

这种编译和执行使得 Python 比 C/C++ 等其他低级语言慢。在C/C++等语言中,源代码被编译成binary code,可以直接被CPU执行,比Python的执行效率更高。

【讨论】:

  • 对不起,但这不是 python 速度较慢的唯一原因。 C/C++ 允许更精确的控制,以确保程序只做我们想做的事,仅此而已。
【解决方案10】:

这个答案适用于 python3。大多数人不知道每当您使用 import 语句时都会发生类似 JIT 的编译。 CPython 将搜索导入的源文件(.py),注意修改日期,然后在名为“_ _ pycache _ _”(dunder pycache dunder)的子文件夹中查找已编译为字节码的文件(.pyc)。如果一切都匹配,那么您的程序将使用该字节码文件,直到发生更改(您更改源文件或升级 Python)

但是这种情况永远不会发生在通常从 BASH shell 以交互方式或通过方式启动的主程序中。这是一个例子:

#!/usr/bin/python3
# title : /var/www/cgi-bin/name2.py
# author: Neil Rieck
# edit  : 2019-10-19
# ==================
import name3  # name3.py will be cache-checked and/or compiled
import name4  # name4.py will be cache-checked and/or compiled
import name5  # name5.py will be cache-checked and/or compiled
#
def main():
    #
    # code that uses the imported libraries goes here
    #
if __name__ == "__main__":
    main()
#

一旦执行,编译后的输出代码将被丢弃。但是,如果您通过如下 import 语句启动,您的主要 python 程序将被编译:

#!/usr/bin/python3
# title : /var/www/cgi-bin/name1
# author: Neil Rieck
# edit  : 2019-10-19
# ==================
import name2    # name2.py will be cache-checked and/or compiled
#name2.main()   #

现在需要注意的是:

  1. 如果您在 Apache 区域中以交互方式测试代码,您的编译文件可能会以 Apache 无法读取(或在重新编译时写入)的权限保存
  2. 有人声称子文件夹“_ _ pycache _ _”(dunder pycache dunder)需要在 Apache 配置中可用
  3. SELinux 是否允许 CPython 写入子文件夹(这是 CentOS-7.5 中的一个问题,但我相信已经提供了一个补丁)

最后一点。您可以自己访问编译器,生成 pyc 文件,然后更改保护位作为我列出的任何警告的解决方法。这里有两个例子:

method #1
=========
python3
import py_compile
py_compile("name1.py")
exit()

method #2
=========
python3 -m py_compile name1.py

【讨论】:

    【解决方案11】:

    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 不是一种缓慢的编程语言

    【讨论】:

    • 欢迎来到 SO。您关于加速 Python 的观点可能是有效的,但不要回答 OP 的问题:“为什么 Python 程序通常比用 C 或 C++ 编写的等效程序慢?”