做实验的时候常常会遇到一个脚本跑的很慢的情况,这个时候我们常常会想方设法的去做一些优化,来让脚本跑的快一些。 但是优化带来了两个问题,一个是优化后的代码仍然是正确的吗,第二个问题是优化有效果吗?
第一个问题可以依靠编写合适的单元测试来解决, 但是究竟如何编写合适的单元测试仍然是一个很大的问题,这个问题我们留待以后在讨论。
第二个问题可以依靠性能分析来解决,性能分析就是测试代码的执行时间,很多时候我们经常会用如下的方式来做性能分析,但是这种方法一来麻烦,二来会把代码弄得很混乱。
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
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