46

有没有人用 Python 编写过代码,结果证明它的执行速度不够快?

我的意思是,您因此而被迫选择另一种语言

我们正在研究将 Python 用于几个较大的项目,我的感觉是,在大多数情况下,Python 对于大多数场景(与 Java 相比)都足够快,因为它依赖于优化的 C 例程。

我想看看人们是否有从 Python 开始的实例,由于性能问题最终不得不使用其他东西。

谢谢。

4

19 回答 19

34

是的,我有。我曾经为二进制(长度前缀而不是分隔)bcp 输出文件编写了一个行计数程序,最后不得不在 C 中重做它,因为 python 太慢了。这个程序很小(用 C 重写只花了几天时间),所以我没有费心去尝试构建一个混合应用程序(用 C 编写的带有中央例程的 python 胶水),但这也有是一条可行的路线。

可以使用 C 和更高级别语言的组合来编写具有性能关键位的大型应用程序。您可以使用 C 语言编写性能关键部分,并为系统的其余部分提供 Python 接口。 SWIGPyrexBoost.Python(如果你使用 C++)都提供了很好的机制来为你的 Python 接口做管道。python的C APITclLua的更复杂,但手工构建并非不可行。有关手动构建的 Python/C API 的示例,请查看cx_Oracle

早在 1970 年代(据我所知),这种方法已被用于相当多的成功应用程序中。 Mozilla基本上是用 Javascript 围绕一个用 C 编写的核心引擎编写的。 几个 CAD 包Interleaf(一个技术文档发布系统),当然还有EMACS基本上是用 LISP 编写的,带有一个中央 C、汇编语言或其他核心。相当多的商业和开源应用程序(例如ChandlerSungard Front Arena)使用嵌入式 Python 解释器并在 Python 中实现应用程序的大部分。

编辑:在回应荷兰大师的评论时,让具有 C 或 C++ 编程技能的人加入 Python 项目的团队可以让您选择编写一些应用程序以提高速度。您可以期望获得显着性能提升的领域是应用程序对大型数据结构或大量数据进行高度迭代的地方。在上面的行计数器的情况下,它必须吸入一系列总计几千兆字节的文件,并经历一个读取可变长度前缀并使用它来确定数据字段长度的过程。大多数字段都很短(只有几个字节长)。这有点麻烦,非常低级和迭代,这使它自然适合 C。

许多 python 库,如numpycElementTreecStringIO使用优化的 C 或 FORTRAN 内核和 python API,便于处理聚合数据。例如,numpy 具有用 C 编写的矩阵数据结构和操作,可以完成所有艰苦的工作,还有一个 Python API 可以在聚合级别提供服务。

于 2008-12-22T16:28:08.517 回答
19

这是一个比人们愿意承认的更难回答的问题。

例如,我可能能够编写一个在 Python 中比在 C 中执行得更好的程序。该陈述的错误结论是“因此 Python 比 C 更快”。实际上,这可能是因为我在 Python 及其最佳实践和标准库方面有更近期的经验。

事实上,除非他们确定可以用两种语言创建最佳解决方案,否则没有人能真正回答您的问题,这是不太可能的。换句话说,“我的 C 解决方案比我的 Python 解决方案快”与“C 比 Python 快”不同

我敢打赌,Guido Van Rossum 可能已经为亚当和达斯汀的问题编写了 Python 解决方案,并且表现相当不错。

我的经验法则是,除非您正在编写需要计算时钟周期的应用程序,否则您可能会在 Python 中获得可接受的性能。

于 2008-12-22T16:40:55.917 回答
15

添加我的 0.02 美元作为记录。

我的工作涉及开发运行超过 100 GB 数据的数字模型。难点在于快速提出创收解决方案(即上市时间)。为了在商业上取得成功,解决方案还必须快速执行(在最短的时间内计算解决方案)。

对我们来说,Python 已被证明是开发解决方案的绝佳选择,原因通常是:快速的开发时间、语言表达能力、丰富的库等。但为了满足执行速度的需求,我们采用了“混合”方法,有几个响应已经提到过。

  1. 将 numpy 用于计算密集的部分。我们将使用 numpy 的“本机”C++ 解决方案的速度提高了 1.1 到 2.5 倍,而且代码更少、错误更少、开发时间更短。
  2. 酸洗(Python 的对象序列化)中间结果以最小化重新计算。我们系统的性质要求对相同数据执行多个步骤,因此我们“记住”结果并在可能的情况下重复使用它们。
  3. 分析和选择更好的算法。在其他回复中已经说过,但我会重复一遍:我们抽出 cProfile 并尝试用更好的算法替换热点。并非在所有情况下都适用。
  4. 去 C++。如果上述失败,那么我们调用 C++ 库。我们使用PyBindGen来编写我们的 Python/C++ 包装器。我们发现它远远优于 SWIG、SIP 和 Boost.Python,因为它可以直接生成 Python C API 代码而无需中间层。

阅读此列表,您可能会想“有多少返工!我将在 [C/C++/Java/assembler] 中第一次完成它并完成它。”

让我把它放在眼里。使用 Python,我们能够在 5 周内生成一个可工作的创收应用程序,而在其他语言中,以前类似范围的项目需要 3 个月的时间。这包括优化我们发现很慢的 Python 部分所需的时间。

于 2009-01-26T04:54:13.443 回答
7

不太远。我在一家拥有分子模拟引擎和一堆用 python 编写的程序来处理大型数 GB 数据集的公司工作。由于开发灵活性和时间方面的巨大优势,我们所有的分析软件现在都是用 Python 编写的。

如果某些东西不够快,我们会使用 cProfile 对其进行分析并找到瓶颈。通常有一个或两个函数会占用 80% 或 90% 的运行时间。然后我们使用这些函数并用 C 重写它们,Python 用它的 C API 使这变得非常容易。在许多情况下,这会导致一个数量级或更多的加速。问题消失了。然后,我们继续愉快地继续用 Python 编写其他所有内容。冲洗并重复...

对于我们倾向于使用 Boost.python 的整个模块或类,它可能有点麻烦,但最终效果很好。如果它只是一个或两个函数,如果项目已经在使用 scipy,我们有时会使用 scipy.weave 内联它。

于 2008-12-22T18:41:19.683 回答
7

在大学期间,我们正在编写一个计算机视觉系统,用于根据视频剪辑分析人类行为。我们使用 Python 是因为 PIL 非常出色,以加快开发速度,让我们可以轻松访问从视频中提取的图像帧,以便转换为数组等。

对于我们想要的 90% 来说,它很好,而且由于图像的分辨率相当低,所以速度还不错。然而,一些过程需要一些复杂的逐像素计算以及众所周知的缓慢的卷积。对于这些特定区域,我们用 C 语言重写了循环的最里面部分,并且只是更新了旧的 Python 函数以调用 C 函数。

这给了我们两全其美。我们拥有 python 提供的数据访问的便利性,这使得开发能够快速,然后是 C 的直线速度,用于最密集的计算。

于 2008-12-22T17:12:50.267 回答
5

每当我发现 Python 瓶颈时,我都会将 C 中的代码重写为 Python 模块。

例如,我有一些硬件将图像像素发送为 4 字节 0RGB。在 Python 中将 8M 从 0RGB 转换为 RGB 耗时太长,因此我将其重写为 Python 模块。

编写 Python(或其他高级语言)比用 C 编写要快得多,所以我一直使用 Python,直到我不能。

于 2008-12-22T18:03:54.983 回答
4

这种问题很可能会在语言人之间引发一场宗教战争,所以让我稍微不同地回答一下。

对于当今计算环境中的大多数情况,您对编程语言的选择应该基于您可以高效编程、编程良好以及让您满意的内容,而不是该语言的性能特征。此外,在对任何系统进行编程时,优化通常应该是最后考虑的问题。

典型的 Python 做事方式是开始用 Python 编写程序,然后如果您注意到性能问题,请分析应用程序并尝试首先优化 Python 中的热点。如果优化 python 代码仍然不够好,那么让你失望的代码区域应该被重写为 C 中的 python 模块。如果即使在所有这些之后你的程序还不够快,你也可以改变语言或查看硬件或并发性的扩展。

这是一个很长的答案,直接回答你的问题;不,python(有时带有 C 扩展)对于我需要它做的所有事情来说已经足够快了。我真正深入了解 C 的唯一一次是访问没有 python 绑定的东西。

编辑:我的背景是一个大型 .com 的 Python 程序员,我们在从我们网站的前端一直到所有后台系统的所有事情上都使用 Python。Python 在很大程度上是一种企业级语言。

于 2008-12-24T03:55:24.447 回答
4

在为特定数据类型实现专门的内存缓存服务器时,存储后端将更有效地使用内存,并且可以通过按位查找操作(即:O(1) 查找)减少查找时间。

我在 2 天内用 Python 编写了所有协议实现和事件驱动的守护程序部分,让我们有足够的时间来测试功能并专注于性能,同时团队正在验证协议一致性和其他位。

鉴于Pyrex之类的工具,对于任何有一点 C 经验的开发人员来说,为 Python 实现 C 扩展都是微不足道的。我用 C 重写了基于Radix Tree的存储后端,并在一天之内用 Pyrex 使其成为 Python 模块。475K 前缀的内存使用量从 90MB 下降到 8MB。我们的查询性能提高了 1200%。

今天,这个应用程序使用pyevent (libevent 的 Python 接口)运行,新的存储后端在一个普通的单核服务器上每秒处理 8000 个查询,作为一个单进程守护进程运行 (感谢 libevent),占用不到 40MB 内存(包括Python 解释器)同时处理 300 多个同时连接。

这是一个在不到 5 天的时间内设计并实施到生产质量的项目。如果没有 Python 和 Pyrex,则需要更长的时间。

我们可以通过使用更强大的服务器并切换到多进程/多实例模型来解决性能问题,同时使代码和管理任务复杂化,同时占用更大的内存。

我认为你在使用 Python 的正确轨道上。

于 2009-03-23T15:12:34.750 回答
2

我在 python 中开发了几年。最近我不得不列出一个目录中的所有文件并构建一个包含文件名、大小、属性和修改日期的结构。我用os.listdirand做到了这一点os.stat。代码非常快,但是目录中的条目越多,我的代码与列出同一目录的其他文件管理器相比变得越慢,所以我使用 SWIG/C++ 重写了代码,并且真的很惊讶代码的速度有多快。

于 2009-02-02T00:56:30.433 回答
2

您始终可以使用 Python 编写应用程序的一部分。并非每个组件都对性能同样重要。Python 很容易与 C++ 本地集成,或通过 Jython 与 Java 集成,或通过 IronPython 与 .NET 集成。

顺便说一句,在某些基准测试中,IronPython 比 Python 的 C 实现更高效。

于 2008-12-22T16:42:26.397 回答
2

我已经工作了一段时间,开发了一个对大型结构化数据进行操作的应用程序,存储在几 GB 厚的数据库中,Python 已经足够好了。该应用程序具有带有大量控件(列表、树、笔记本、虚拟列表等)的 GUI 客户端和控制台服务器。

我们遇到了一些性能问题,但这些问题主要与糟糕的算法设计或数据库引擎限制(我们使用 Oracle、MS-SQL、MySQL 并且与用于速度优化的 BerkeleyDB 的关系很短)有关,而不是与 Python 本身有关。一旦您知道如何正确使用标准库(用 C 语言编写),您就可以让您的代码变得非常快。

正如其他人所说 - 任何计算密集型算法、依赖于位填充的代码、一些内存受限的计算 - 都可以在原始 C/C++ 中完成以节省 CPU/内存(或任何其他技巧),但整个用户交互、日志记录、数据库处理、错误处理——所有使应用程序真正运行的东西,都可以用 Python 编写,它将保持响应能力和良好的整体性能。

于 2008-12-22T17:05:58.563 回答
2

我曾经在 python 中制作过很多东西的原型,用于做日志处理之类的事情。当它们运行得不够快时,我会用 ocaml 重写它们。

在很多情况下,python 都很好,我对此很满意。在某些情况下,当它开始接近 23 小时来完成一天的日志时,我会开始重写。:)

我想指出,即使在这些情况下,我最好还是只分析 python 代码并找到一个更快乐的 python 实现。

于 2008-12-22T16:34:44.023 回答
2

是的,两次:

  • 我用 C++ 完全重写了一个音频 DSP 应用程序,因为我无法在 Python 中获得适当的性能;我不认为 Python 实现是浪费的,因为它让我可以很容易地对概念进行原型设计,并且 C++ 移植进展顺利,因为我有一个工作参考实现。

  • 一个程序图形渲染项目,在 Python 中生成大型 2D 纹理贴图需要很长时间;我编写了一个 C++ DLL 并使用 ctypes/windll 从 Python 中使用它。

于 2010-06-25T23:55:49.173 回答
1

不,我从来不需要重写。事实上,我从 Maya 8.5 开始使用 Python。在 Maya 8 之前,唯一可用的脚本语言是内置的 MEL(Maya 表达式语言)。Python 实际上比它包装的内置语言更快。

Python 处理复杂数据类型的能力也使其速度更快,因为 MEL 只能存储一维数组(并且没有指针)。这需要通过使用多个并行数组或使用慢速字符串连接来伪造多维数组。

于 2008-12-23T02:14:06.447 回答
1

一个月前,我有一个用 Python(用于工作)编写的分析日志的小程序。当日志文件的数量增加时,程序开始变得非常慢,我想我可以用 Java 重写它。

我很有趣。将相同的算法从 Python 迁移到 Java 花了一整天的时间。一天结束时,一些基准测试清楚地向我表明,Java 程序比 Python 程序慢了 20% / 25%。这对我来说是一个惊喜。

第二次编写该算法也向我展示了一些优化是可能的。所以在两个小时内我用 Python 完全重写了整个东西,它比原来的 Python 实现快了大约 40%(因此比我的 Java 版本快了几个数量级)。

所以:

  1. Python 是一种慢速语言,但对于某些任务,它仍然可以比其他本应更快的语言更快

  2. 如果您必须花时间用一种执行速度更快但开发时间更慢的语言(大多数语言)编写一些东西,请考虑使用同一时间来分析问题、搜索库、配置文件,然后编写更好的 Python 代码。

于 2008-12-25T20:57:40.577 回答
1

我曾经不得不为模拟器编写一个伪随机数生成器。我先用 Python 写的,但事实证明 Python 太慢了;我最终用 C 重写了它,即使这样也很慢,但没有 Python 慢。

幸运的是,桥接 Python 和 C 相当容易,所以我能够将 PRNG 编写为 C 模块,并且仍然用 Python 编写模拟器的其余部分。

于 2008-12-25T21:29:04.570 回答
1

以下链接提供了多种计算机语言之间的持续比较。它应该让您了解 Python 在不同问题领域中的一些优势和劣势。

计算机语言基准游戏

于 2008-12-29T07:56:05.330 回答
1

我正在用Python 重写名为Erok的 Perl 程序OpenKore(与原始Kore相反)。到目前为止,Python 被证明是一种整体上更好的语言,特别是因为它强大的字符串解析功能不需要使用正则表达式,这确实加快了它的文件解析速度。

于 2008-12-29T08:07:11.890 回答
0

我通常不会在我之前重写为 C:

  • 轮廓
  • 用更好的算法重写(通常这就足够了)
  • 考虑到低级性能重写python代码(但永远不要使用非pythonic/非可读代码)
  • 花一些时间重新检查一个库不能做到这一点(首先在 stdlib 或外部库中)
  • 尝试了 psyco / 其他实现(在我的情况下很少实现真正的速度提升)

然后有时我创建了一个共享库来执行繁重的矩阵计算代码(不能用 numarray 完成)并用 ctypes 调用它:

  • 用纯 C 编写/构建/测试 .so / dll 很简单,
  • 将 C 封装为 python 函数很简单(即,如果您使用基本数据类型,则不需要,因为 ctypes 会为您完成调用正确参数的所有工作),而且速度肯定足够快。
于 2009-12-14T10:09:46.097 回答