加速Python

时间:2008-10-05 21:46:00

标签: python optimization performance

这实际上是两个问题,但它们非常相似,为了保持简单,我想我只是把它们放在一起:

  • 首先:鉴于已经建立的python项目,除了简单的代码内优化之外,有什么方法可以加快速度?

  • 其次:在python中从头开始编写程序时,有哪些好方法可以大大提高性能?

对于第一个问题,假设您获得了一个写得很好的项目,并且您需要提高性能,但您似乎无法通过重构/优化获得很多收益。在这种情况下,你会做些什么来加速它,而不是用C语言重写它?

19 个答案:

答案 0 :(得分:41)

关于“其次:在python中从头开始编写程序时,有哪些好方法可以大大提高性能?”

记住杰克逊的优化规则:

  • 规则1:不要这样做。
  • 规则2(仅限专家):不要这样做。

Knuth规则:

  • “过早优化是万恶之源。”

General Rules for Optimization中有更多有用的规则。

  1. 不要随意优化。首先要做对。然后快点。优化错误的程序仍然是错误的。

  2. 记住80/20规则。

  3. 始终运行“之前”和“之后”基准。否则,你不会知道你是否找到了80%。

  4. 使用正确的算法和数据结构。这个规则应该是第一个。没有什么比算法和数据结构更重要了。

  5. 底线

    您无法阻止或避免“优化此计划”的努力。这是工作的一部分。您必须对其进行规划并仔细进行,就像设计,代码和测试活动一样。

答案 1 :(得分:26)

我建议:

,而不仅仅是向C广告

让你的代码计数。使用更少的行执行做更多事情:

  • 将算法更改为更快的算法。在许多情况下,它并不需要更快。
  • 使用恰好用C语言编写的python原语。有些东西会迫使解释器发送到某些地方。后者是优选的
  • 注意首先构建大数据结构然后使用其消耗的代码。想想范围和xrange之间的区别。通常,通常值得考虑程序的内存使用情况。使用生成器有时可以将O(n)内存使用降低到O(1)。
  • Python通常是非优化的。从循环中提升不变代码,在紧密循环中尽可能消除常见的子表达式。
  • 如果某些东西很贵,那么预计算或记忆它。例如,可以编译正则表达式。
  • 需要紧缩数字?您可能需要检查numpy
  • 许多python程序很慢,因为它们受磁盘I / O或数据库访问的约束。确保在等待数据到达而不仅仅是阻止时有值得做的事情。武器可能类似于Twisted框架。
  • 请注意,许多关键的数据处理库都有C版本,无论是XML,JSON还是诸如此类的东西。它们通常比Python解释器快得多。

如果以上所有内容都无法用于配置文件和测量代码,那么就开始考虑C重写路径。

答案 2 :(得分:23)

通常的嫌疑人 - 描述它,找到最昂贵的线路,弄清楚它在做什么,修复它。如果你之前没有做太多的分析,可能会有一些大的二次循环或字符串重复隐藏在其他看似无害的表达式之后。

在Python中,我发现非明显减速的两个最常见的原因是字符串连接和生成器。由于Python的字符串是不可变的,所以做这样的事情:

result = u""
for item in my_list:
    result += unicode (item)

每次迭代将复制整个字符串两次。这已经很好地解决了,解决方案是使用"".join

result = "".join (unicode (item) for item in my_list)

发电机是另一个罪魁祸首。它们非常易于使用并且可以极大地简化某些任务,但是应用程序不良的生成器将比仅仅将项目附加到列表并返回列表要慢得多。

最后,不要害怕在C中重写位! Python作为一种动态的高级语言,根本无法匹配C的速度。如果有一个函数无法在Python中进行优化,请考虑将其解压缩到扩展模块。

我最喜欢的技术是维护模块的Python和C版本。编写的Python版本尽可能清晰明了 - 任何错误都应该易于诊断和修复。针对此模块编写测试。然后编写C版本并进行测试。它的行为应该在所有情况下都与Python实现的行为相同 - 如果它们不同,应该很容易找出哪个是错误的并纠正问题。

答案 3 :(得分:17)

首先想到的是:psyco。它暂时仅在x86上运行。

然后,constant binding。也就是说,使所有全局引用(以及 global.attr global.attr.attr ...)成为函数和方法中的本地名称。这并不总是成功的,但总的来说它是有效的。它可以手工完成,但显然很乏味。

你说除了代码内优化之外,所以我不会深入研究这个问题,但是请注意人们常常犯的典型错误(for i in range(10000000))。

答案 4 :(得分:9)

Cython和pyrex可用于使用类似python的语法生成c代码。 Psyco对于合适的项目来说也是很棒的(有时你不会注意到速度提升很多,有时它会快50倍)。 我仍然认为最好的方法是分析你的代码(cProfile等),然后将瓶颈编码为python的c函数。

答案 5 :(得分:7)

我很惊讶没有人提到ShedSkin:http://code.google.com/p/shedskin/,它会自动将你的python程序转换为C ++,并且在某些基准测试中比psyco在速度方面产生更好的改进。

关于简洁性的轶事故事:http://pyinsci.blogspot.com/2006/12/trying-out-latest-release-of-shedskin.html

但有一些限制,请参阅:http://tinyurl.com/shedskin-limitations

答案 6 :(得分:5)

我希望你读过:http://wiki.python.org/moin/PythonSpeed/PerformanceTips

恢复已经存在的原则通常有3个原则:

  • 编写在更好的字节码中转换的代码,比如,使用本地,避免不必要的查找/调用,使用惯用的构造(如果有你想要的自然语法,使用它 - 通常更快。例如:不要这样做:“对于some_dict.keys()中的键,“,do”for some_dict中的键“)
  • 用C语言编写的内容要快得多,滥用任何可用的C函数/模块
  • 如有疑问,请导入timeit,profile

答案 7 :(得分:4)

这不一定会加速您的任何代码,但如果您想避免减慢代码速度,那么在使用Python编程时这是一项关键知识。如果不了解它的行为,那么“全局解释器锁定”(GIL)有可能大大降低多线程程序的速度(是的,这就是我...我有一台不错的4处理器机器,不会一次使用超过1.2个处理器)。这是一篇介绍性文章,其中包含一些链接,可以帮助您开始SmoothSpan

答案 8 :(得分:4)

通过Python分析器运行您的应用。 找个严重的瓶颈。 重写C中的瓶颈。 重复。

答案 9 :(得分:4)

人们给了一些很好的建议,但是你必须要知道,当需要高性能时,python模型是:punt to c。像psyco这样的努力可能会在将来有所帮助,但是python并不是一种快速的语言,而且它的设计并非如此。很少有语言能够很好地完成动态内容并且仍能生成非常快的代码;至少在可预见的未来(以及一些反对快速编译的设计工作)中都是如此。

所以,如果你真的发现自己处于这种绑定状态,那么最好的办法就是隔离系统中那些(好)python中不可接受的部分,并围绕你在C中重写这些位的想法进行设计。对不起好的设计可以帮助减少痛苦。首先在python中对它进行原型设计,然后你也很容易对你的c进行健全性检查。

毕竟,这对于像numpy这样的东西来说效果还不错。我不能强调有多好的设计会对你有所帮助。如果你只是迭代地戳你的python位并用C代替最慢的那些,你可能会陷入一团糟。仔细考虑需要C位的位置,以及如何最小化和封装它们。

答案 10 :(得分:3)

这是我尝试遵循的程序:

     
  • 导入psyco; psyco.full()  
  • 如果速度不够快,请通过分析器运行代码,查看瓶颈所在。 (禁用psyco这一步!)  
  • 尝试做其他人提到的事情,尽快让代码处于这些瓶颈。  
    • 像[str(x)for x in l]或[x.strip()for x in l]这样的东西比map(str,x)或map(str.strip,x)慢得多)。
     
  • 在此之后,如果我仍然需要更高的速度,实际上很容易让PyRex启动并运行。我首先复制一段python代码,直接把它放在pyrex代码中,看看会发生什么。然后我旋转它直到它变得越来越快。

答案 11 :(得分:3)

通过使用内置Python调用的隐式算法替换在Python中手写的显式算法,通常可以实现近C速度(对于任何使用Python的项目来说足够接近!)。这是有效的,因为大多数Python内置函数无论如何都是用C语言编写的。好吧,当然在CPython中;-) https://www.python.org/doc/essays/list2str/

答案 12 :(得分:3)

关于使用psyco的说明:在某些情况下,它实际上可以产生较慢的运行时间。特别是当尝试使用用C语言编写的代码时,我不记得我读过这篇文章,但map()reduce()函数是专门提到的。幸运的是,你可以告诉psyco不要处理指定的功能和/或模块。

答案 13 :(得分:2)

这里有关于如何改进Python代码的规范性参考:PerformanceTips。除非你确实需要,否则我建议不要在C中进行优化。对于大多数应用程序,您可以按照该链接中发布的规则获得所需的性能。

答案 14 :(得分:1)

如果使用psyco,我建议使用psyco.profile()代替psyco.full()。对于一个更大的项目,它将更加智能,优化的功能和使用更少的内存。

我还建议查看迭代器和生成器。如果您的应用程序使用大型数据集,这将为您节省许多容器副本。

答案 15 :(得分:1)

除了(好)psyco和(好)shedskin之外,我建议您尝试使用cython作为pyrex的一个很好的分支。

或者,如果你不赶时间,我建议你等一下。较新的python虚拟机即将推出,unladen-swallow将进入主流市场。

答案 16 :(得分:0)

在提出这个问题之后,引入了几种加速Python代码的方法:

  • Pypy 有一个JIT编译器,这使得CPU绑定代码的速度更快。
  • Pypy是用Rpython编写的,这是Python的一个子集,它编译为本机代码,利用LLVM工具链。

答案 17 :(得分:0)

对于已建立的项目,我觉得主要的性能提升将来自尽可能多地使用python内部库。

这里有一些提示:http://blog.hackerearth.com/faster-python-code

答案 18 :(得分:0)

还有Python → 11l → C++ transpiler,可以从here下载。