Skip to content

Instantly share code, notes, and snippets.

@zhuang-hao-ming
Last active December 8, 2022 09:39
Show Gist options
  • Save zhuang-hao-ming/dbc2bf12e317725c2c05aae45f319acc to your computer and use it in GitHub Desktop.
Save zhuang-hao-ming/dbc2bf12e317725c2c05aae45f319acc to your computer and use it in GitHub Desktop.
如何对python代码做性能分析

做实验的时候常常会遇到一个脚本跑的很慢的情况,这个时候我们常常会想方设法的去做一些优化,来让脚本跑的快一些。 但是优化带来了两个问题,一个是优化后的代码仍然是正确的吗,第二个问题是优化有效果吗?

第一个问题可以依靠编写合适的单元测试来解决, 但是究竟如何编写合适的单元测试仍然是一个很大的问题,这个问题我们留待以后在讨论。

第二个问题可以依靠性能分析来解决,性能分析就是测试代码的执行时间,很多时候我们经常会用如下的方式来做性能分析,但是这种方法一来麻烦,二来会把代码弄得很混乱。

from time import time

begin_tick = time()
...
print(time()-begin_tick)

我通过搜索找了两个方法来对python程序做性能分析。

以后一定要彻底告别使用time

函数级别分析

性能分析应该由大到小逐步分析, 所以首先应该分析函数级别的性能。

python标准库带了一个cProfile模块可以用来做函数级别的性能分析。 使用如下代码,就可以生成一份性能分析报告到output.prof中。

python -m cProfile -o output.prof main.py

output.prof是一个二进制文件,标准库中有pstats模块可以查看这个文件的内容,但是文本的东西还是不够直观, 可以使用snakeviz模块来可视化分析结果。 使用如下代码,就会自动弹出一个浏览器窗口显示相应的分析内容,snakeviz的文档比较清晰的说明了相应的用法。

snakeviz output.prof

qq 20180725212951

行级别的分析

cProfile只能分析显式的函数调用,有的时候一个函数可能很长,单单阅读源代码很难发现究竟哪个部分是性能瓶颈, 而且可能存在一个语句运行很久的情况,特别是在科学计算中(比如确定一个元素是否在一个大的列表中存在,numpy的大矩阵运算等)。 这个时候需要具体分析每一行代码的性能。

line_profiler模块就是实现这个目的的。

通常我们已经进行了函数级别的性能分析,知道性能瓶颈是在那一个函数上,所以需要在要分析的函数上添加一个装饰器,如下所示。

@profile
def main():
....

然后运行程序,就会自动生成一个分析报告,报告的名字为main.py.lprof

kernprof -l main.py

报告同样是二进制格式的,需要使用相应的模块来查看,虽然没有相应的可视化浏览器,但是line_profiler提供的 可视化仍然十分清晰。使用如下代码就会在控制台显示分析内容。

python -m line_profiler script_to_profile.py.lprof

qq 20180725214706

参考

  1. snakeviz的主页
  2. line_profiler的主页
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment