使用C扩展或Cython优化复杂Python应用程序的教程

25

Python社区提供了有用的参考资料,展示了如何对Python代码进行性能分析,以及C或Cython中Python扩展的技术细节。但是,对于非平凡的Python程序,我仍在寻找以下内容的教程:

  1. 如何识别将受益于转换为C扩展的热点
  2. 同样重要的是,如何确定不会受益于转换为C扩展的热点
  3. 最后,如何使用Python C-API或(可能更好的选择)使用Cython从Python适当地转换为C。

一个好的教程应该为读者提供一种通过解决完整示例来理解优化问题的方法论。我没有找到这样的资源。

您是否知道(或已经编写)此类教程?

为澄清起见,我不感兴趣的教程仅包括以下内容:

  • 使用(c)Profile对Python代码进行性能分析以测量运行时间
  • 使用工具来检查配置文件(我推荐RunSnakeRun
  • 通过选择更合适的算法或Python构造(例如,用于成员资格测试的集合而不是列表)进行优化;教程应该假设算法和Python代码已经是最优的,并且我们已到达一个将C扩展作为下一步的逻辑点。
  • 重申Python编写C扩展的文档,这已经作为参考文献非常出色,但不适合作为说明何时以及如何从Python转向C的资源。
4个回答

9

第1点和第2点只是基本的优化准则。如果有你要找的那种教程,我会非常惊讶。也许这就是你没有找到的原因。我的简短列表:

  • 优化的第一条规则是不要优化
  • 优化的第二条规则是测量
  • 优化的第三条规则是确定限制因素(如果是IO或数据库绑定,则任何优化都可能无法达到)。
  • 优化的第四条规则是思考使用更好的算法和数据结构...
  • 考虑更改语言的可能性在列表中相当低...
只需使用通常的Python工具对您的Python代码进行分析,找出需要优化的地方。然后尝试在Python中进行优化。如果速度仍然太慢,请尝试理解原因。如果是IO限制,则不太可能用C程序更好。如果问题来自算法,则C性能也不太可能更好。实际上,“好”的情况下C可以提供帮助相当少,运行时应该与您想要的(如2或3倍的加速)差不多,数据结构简单,并且会从低级表示中受益并且确实需要那种加速。在大多数其他情况下,使用C而不是Python将是一项没有回报的工作。
实际上,调用C代码以实现Python的主要目标并非始终是为了提高性能。更经常的目标是将Python与某些现有的C代码进行接口。
正如其他帖子所说,您最好使用cython。
如果您仍想为Python编写C模块,则所有必要的信息都在官方文档中。

我想补充一下,你在某些任务中会需要使用SWIG或Boost::Python。 - Jake Kurzer
1
在编程中,算法比语言更重要。而对于考虑C的优势来说——它擅长在紧密循环中操作简单的低级数据结构。 - tobyodavies

6

O'Reilly有一个教程(据我所知是免费的,我能够阅读整个教程),介绍了如何对真实项目进行性能分析(他们使用EDI解析项目作为性能分析的主题)并识别热点。在O'Reilly文章中,关于编写C扩展程序以消除瓶颈的细节不是很多。但是,它用一个非平凡的示例涵盖了你想要的前两个步骤。

编写C扩展程序的过程已经有相当详细的文档这里。难点在于找到一种方法来复制Python代码在C中的执行方式,这需要创新、算法、硬件和效率方面的知识以及相当的C技能,而这些都很难在教程中教授。

希望这可以帮助您。


一般来说,我喜欢Jeremy Jones的Python文章,但这篇文章比较弱。正如你所指出的,它只讨论了剖析和优化算法,并没有进一步展示如何通过编写扩展来进行优化。此外,我认为hotshot模块已经被弃用,因为它在Python 3中已从标准库中删除;应该使用cProfile代替。 - gotgenes

4
对于第一点和第二点,我会使用Python分析器,例如cProfile。在这里可以看到一个快速教程:here
如果你已经有了一个现成的Python程序,在第三点上,你可能想考虑使用Cython。当然,与其重写为C语言,你可能能想出一种算法改进来提高执行速度。

你能推荐一个教程,演示如何通过使用Cython重新编写(部分)纯Python程序来进行优化吗? - gotgenes

2
我将尝试回答您的第1和第2个问题以及前3个要点,但不按顺序。
第3个要点说“假设算法和Python代码已经是最优的”。当代码处于这种状态时,如果取样堆栈(如这里所述),样本将显示程序从时间角度正在执行的内容,并且似乎没有任何可以改进而不更改语言的地方。然而,由于您知道它花费时间的方式,因此您知道哪些低级算法(可能包括多个函数,而不仅仅是热点)可以通过减少时间来受益,即通过转换为C。
关于第1点,该方法显示哪些代码部分将受益于转换为C,它们可能是热点,也可能不是。(首先想到的是任何递归函数或一组函数。或者,一小组函数共同完成某个目的,例如山岳攀登者。)
关于第2点,任何不出现在大部分堆栈样本中的代码,或者虽然出现在堆栈样本中,但明显不会从转换为C中受益的代码,例如I/O。
关于第1和第2个要点,我同意测量不是主要目标,而是找到优化代码的过程的副产品。呈现这些测量结果也没有意义。
我曾经遇到过类似的情况,只不过不是在Python和C之间,而是在C和硬件之间。**
举个例子,如果总运行时间为10秒,并且算法大约占堆栈的50%,则它负责大约5秒钟。如果将算法转换为C可以使速度提高10倍,则这5秒钟将缩短为0.5秒钟,因此总时间将缩短为5.5秒钟。(大致如此-更重要的是实现时间缩短,而不是事先精确知道缩短的大小。)注意,在此时,整个过程可以重复进行,可能还有其他代码需要转换为C。当样本显示Python代码正在执行其擅长的操作,而C代码正在执行其擅长的操作时,您可以停止此过程。
**例如,浮点数运算,库与芯片之间的比较或图形,绘制文本和多边形。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接