Python性能分析

2023-12-13 7:20:27网络知识匿名

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培训机构:瀚银百科。

发表评论: