python标准库提供两个代码性能分析相关的模块,即timeit和cProfile/profile。前者更适合测试简短的代码片段,后者则可分析代码片段乃至整体模块中各个函数的调用次数、运行耗时等信息。
cProfile是profile的C版本,开销更小。基于cProfile模块,可方便地评估程序性能瓶颈(bottleneck),借以发现程序中值得优化的短板。
根据粒度不同,可将cProfile使用场景分为三类。
1.1分析单条语句
importcProfile,pstats,re,cStringIO
cProfile.run('re.compile("foo|bar")','prfRes')#将cProfile的结果写入prfRes文件
p=pstats.Stats('prfRes')#pstats读取cProfile输出结果
#strip_dirs()剥除模块名的无关路径(如C:\Python27\lib\)
#sort_stats('cumtime')或sort_stats('cumulative')按照cumtime对打印项排序
#print_stats(n)打印输出前10行统计项(不指定n则打印所有项)
p.strip_dirs().sort_stats('cumtime').print_stats(5)
pstats模块可用多种方式对cProfile性能分析结果进行排序并输出。运行结果如下:
TueMay2413:56:072016prfRes
195functioncalls(190primitivecalls)in0.001seconds
Orderedby:cumulativetime
Listreducedfrom33to5duetorestriction<5>
ncallstottimepercallcumtimepercallfilename:lineno(function)
10.0000.0000.0010.001:1()
10.0000.0000.0010.001re.py:192(compile)
10.0000.0000.0010.001re.py:230(_compile)
10.0000.0000.0010.001sre_compile.py:567(compile)
10.0000.0000.0000.000sre_compile.py:552(_code)
其中,tottime表示某函数的总计运行时间(不含该函数内调用的子函数运行时间),cumtime表示某函数及其调用的子函数的累积运行时间。
1.2分析代码片段
pr=cProfile.Profile()
pr.enable()#以下为待分析代码段
regMatch=re.match('^([^/]*)/(/|\*)+(.*)$','/\*.*\*/匹配单行注释()并替换为空字符,用^\s*//.*$匹配单行注释(//abc)并替换为空字符。然后,查找并手工删除跨行注释及其他未匹配到的单行注释。最后,选择UltraEdit正则表达式引擎,用%[^t]++^p匹配空行并替换为空字符,即可删除所有空行。注意,UEStudio帮助中提供的正则表达式^p$一次只能删除一个空行。
按上述方式处理两个大型文件后,初步发现BCLineCounter.py关于有效代码行数的统计是正确的。然而,这种半人工处理方式太过低效,因此作者想到让两个脚本处理相同的文件,并输出有效代码行或纯注释行的内容,将其通过AraxisMerge对比。该工具会高亮差异行,且人工检查很容易鉴别正误。此处,作者假定对于给定文件的给定类型行数,BCLineCounter.py和CLineCounter.py必有一者统计正确(可作基准)。当然,也有可能两者均有误差。因此,若求保险,也可同时输出类型和行内容,再行对比。
综合检查结果发现,BCLineCounter.py较CLineCounter.py更为健壮。这是因为,模式匹配需要处理的场景繁多,极易疏漏。例如,CLineCounter.py无法正确处理下面的代码片段:
voidtest(){
inta=1/2;//comment
//*Assignavalue
}
读者若有兴趣,可修改和调试CLineCounter.py里的正则表达式,使该脚本高效而健壮。
以上内容为大家介绍了Python性能分析,希望对大家有所帮助,如果想要了解更多Python相关知识,请关注IT培训机构:瀚银百科。