对代码优化的前提是需要了解性能瓶颈在什么地方,程序运行的主要时间是消耗在哪里,对于比较复杂的代码可以借助一些工具来定位。本文主要讨论如何在项目中测试Python瓶颈函数,对于模块化程度比较好的项目运用如下方法测试会得到比较好的效果.
测试的方法大致如下:利用profile对每个 python 模块进行测试(具体显示可以采用文本报表或者图形化显示),找到热点性能瓶颈函数之后,再利用 line_profiler 进行逐行测试,寻找具有高 Hits 值或高 Time 值的行,最后把需要优化的行语句通过例如Cython之类的优化工具进行优化
(1)利用profile分析相关的独立模块
利用profile分析相关的独立模块,python内置了丰富的性能分析工具,profile,cProfile与hotshot等。其中Profiler是python自带的一组程序,能够描述程序运行时候的性能,并提供各种统计帮助用户定位程序的性能瓶颈。Python标准模块提供三profilers:cProfile,profile以及hotshot。profile是python的标准库。可以统计程序里每一个函数的运行时间,并且提供了多样化的报表。使用profile来分析一个程序很简单,profile可以直接用python解释器调用profile模块来剖分py程序,如在命令行界面输入如下命令:
python -m cProfile profileTest3.py
输出的形式如下所示:
其中输出每列的具体解释如下:
●ncalls:表示函数调用的次数;
●tottime:表示指定函数的总的运行时间,除掉函数中调用子函数的运行时间;
●percall:(第一个percall)等于tottime/ncalls;
●cumtime:表示该函数及其所有子函数的调用运行的时间,即函数开始调用到返回的时间;
●percall:(第二个percall)即函数运行一次的平均时间,等于cumtime/ncalls;
●filename:lineno(function):每个函数调用的具体信息
三者对比:profile速度很慢,只能用于一些小的脚本测试,测试大一点的benchmark往往需要十几分钟甚至更多时间。hotshot和cProfile是用C实现的,所以速度比较快。hotshot有一个缺点是它不支持多线程编程,而且在python2.5以后已经不再维护,较新的版本已经不支持。cProfile相比其它两者有速度快而且能够适用所以版本
(2)通过pstats进行文本报表分析 或者 使用gprof2dot进行报表图形树分析
直接使用profile展示出出来的结果很不明朗,需要自己去慢慢找那些模块占用的时间比较多,我们可以先
把这个文件编译成为中间结果,使用命令python -m cProfile -o funb.prof profileTest3.py
然后可以通过pstats模块进行文本报表分析,它支持多种形式的报表输出,是文本界面下一个较为实用的工具。pstats模块里的有两个有用的函数sort_stats()和t_stats()接受一个或者多个字符串参数,如”time”、”name”等,表明要根据哪一列来排序,这相当有用,例如我们可以通过用time为key来排序得知最消耗时间的函数,也可以通过cumtime来排序,获知总消耗时间最多的函数。另一个相当重要的函数就是print_stats——用以根据最后一次调用sort_stats之后得到的报表。print_stats有多个可选参数,用以筛选输出的数据;
利用这些函数编写一个文本报表分析的脚本如下(这个脚本的含义就是对刚刚的中间结果进行分析,输出函数运行总时间最大的前十个函数)
运行这个脚本:
这些运行结果明朗很多,前面几个函数就是热点瓶颈函数
对于C/C++项目可以利用 gprof2dot 和 graphviz 图形化定位 linux c/c++系统性能瓶颈,对于 python 也是如此。gprof2dot.py 脚本是一个广泛应用的性能测试工具,它既可以和 gprof 结合测 C/C++程序的热点函数,也能和 cProfile 结合测试 Python 项目。文本格式的报告,对于小规模的程序已经足够了,但是对于大规模的程序来说,就显得还是太繁杂了,特别是我们把注意力放在调用关系上时,文本的跳跃总是让人不舒服,gprof2dot.py 程序用于将性能分析结果转化为 dot 文件。dot 是一种编写绘图脚本的语言,它属于 graphviz 软件,它可以很直观的显示运行时的程序流程图,然后很直观的看出每个步骤的占用时间百分比,函数调用次数,颜色能直观的表示出瓶颈所在。使用它需要下载安装 graphviz 软件包,下载 gprof2dot.py 文件,把它的安装路径放入环境变量中。
使用 cProfile 结合gprof2dot.py 脚本方法如下:
测试pybench中的List.py 输入命令
python -m cProfile -o output.pstats profileTest3.py
python gprof2dot.py -f pstats output.pstats | dot -Tpng -o profiling_results.png
执行成功后会将性能分析结果保存在.png 文件中
打开png文件将显示出来报表树
局部图
每个节点的说明如下:
+----------------------------------+
|
function name : module name
|
| total time including sub-calls % | total time including sub-calls %
|
(self execution time %)
|------------------------------------>
| total number of self calls
|
+----------------------------------+
显示的程序执行过程完全对应,清晰明了,每个方框内部显示函数名称,函数整体包括内部子函数占用时间%比,函数自身,不包括内部子函数占用时间%比,函数执行次数。边表示父函数调用该子函数占用的时间%比,调用次数。之所以清晰是因为,gprof2dot默认是部分函数调用图,对性能影响不大的函数调用都不显示。而且函数的所占用时间决定了它的颜色,用红色,绿色标注的都是热点函数,其次是蓝色
(3)通过line_profiler对热点函数进行逐行分析
在检测出来耗时比较大的瓶颈函数后,需要进一步细化测试在一个瓶颈函数中哪些语句调用次数最多耗时最大。这
些语句是可以通过优化带来最大改善的地方。测试的方法是使用一个 line_profiler 的项目来查看脚步中每行代码多快
多频繁的被执行。
使用方法具体介绍如下:
首先通过 pip 安装该 python 包 $ pip install line_profiler
一旦安装完成,你将会使用一个称做“line_profiler”的新模组和一个“kernprof.py”可执行脚本。想要使用该工具,首先修改
你的源代码,在想要测量的函数上装饰@profile 装饰器。不要担心,你不需要导入任何模组。kernprof.py 脚本将会在执
]行的时候将它自动地注入到你的脚步的运行时。
测试过程需要在要测试的脚本文件第一行设置好@profile 装饰器,然后使用 kernprof.py
执行你的脚本
执行命令 python kernprof.py -l -v primes.py
输出结果如下图:
分析输出结果寻找具有高 Hits 值或高 Time 值的行。这些就是可以通过优化带来最大改善的地方。这个脚本的第
8行,第 16,17,18 行是需要进行改进优化的地方
综上所述,对于 python 项目进行性能测试的方法,可以应用测试benchmark 的方法对于项目中每个 python 模块进
行测试(具体显示可以采用文本报表或者图形化显示),找到热点性能瓶颈函数之后,再利用 line_profiler 进行逐行测
试,寻找具有高 Hits 值或高 Time 值的行,最后把需要优化的行语句通过例如Cython之类的优化工具进行优化即可
来源:CSDN
作者:wuChen4646
链接:https://blog.csdn.net/u010786109/article/details/43374227