本节书摘来自异步社区《Python高性能编程》一书中的第2章,第2.6节,作者[美] 戈雷利克 (Micha Gorelick),胡世杰,徐旭彬 译,更多章节内容可以访问云栖社区“异步社区”公众号查看。
2.6 使用cProfile模块
cProfile是一个标准库内建的分析工具。它钩入CPython的虚拟机来测量其每一个函数运行所花费的时间。这一技术会引入一个巨大的开销,但你会获得更多的信息。有时这些额外的信息会给你的代码带来令人惊讶的发现。
cProfile是标准库内建的三个分析工具之一,另外两个是hotshot和profile。hotshot还处于实验阶段,profile则是原始的纯Python分析器。cProfile具有跟profile一样的接口,且是默认的分析工具。如果你对这些库的历史感兴趣,你可以去看一下Armin Rigo在2005年要求将cProfile包含进标准库的请求(http://bit.ly/cProfile_request)。
分析工作的一个好的实践是在开始分析之前先对你的代码各部分的运行速度进行假设。Ian喜欢将有问题的代码打印出来并加以标注。提前生成一个假设意味着有可能测出你错的有多离谱(而且真的会测出!)并提升你对于某种编程风格的直觉。
警告
永远不要忽视靠直觉进行的性能分析(虽然你一定会犯错!)。在分析前先进行假设是绝对值得的,因为这样可以帮助你学习如何定位你代码中可能有问题的地方,而且你应该始终用证据来证明你的选择。
始终基于你的测量结果,用一些既快且脏的分析手段确保你正在分析正确的地方。没有什么比在聪明地优化了一段代码之后(可能过了几小时或几天)才意识到你其实漏掉了进程最慢的部分且根本没有找到真正的问题所在更令人羞愧的了。
那么我们的假设是什么呢?我们知道calculate_z_serial_purepython可能是代码最慢的部分。我们在那个函数里做了大量的解引用并多次调用基本的算术操作和abs函数。这些可能都是耗CPU资源的大户。
这里,我们用cProfile模块运行我们的代码的一个变种。其输出是格式化的,方便我们搞清去哪里做进一步分析。
-s cumulative开关告诉cProfile对每个函数累计花费的时间进行排序,这能让我们看到代码最慢的部分。cProfile会将输出直接打印到屏幕:
$ python -m cProfile -s cumulative julia1_nopil.py
...
36221992 function calls in 19.664 seconds
Ordered by: cumulative time
Ncalls tottime percall cumtime percall filename:lineno(function)
1 0.034 0