Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。
描述Python程序运行时间的好方法是什么?
当前回答
当我不是服务器的根用户时,我使用lsprofcalltree.py并像这样运行我的程序:
python lsprofcalltree.py -o callgrind.1 test.py
然后我可以用任何callgrind兼容的软件打开报告,比如qcachegrind
其他回答
不久前,我制作了pycallgraph,它从您的Python代码生成可视化。编辑:我已经将示例更新为使用3.3,这是本文撰写时的最新版本。
在pip安装pycallgraph并安装GraphViz之后,您可以从命令行运行它:
pycallgraph graphviz -- ./mypythonscript.py
或者,您可以分析代码的特定部分:
from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput
with PyCallGraph(output=GraphvizOutput()):
code_to_profile()
其中任何一个都将生成类似下图的pycallgraph.png文件:
Python包括一个名为cProfile的分析器。它不仅给出了总的运行时间,而且还分别计算了每个函数的时间,并告诉每个函数被调用了多少次,从而很容易确定应该在哪里进行优化。
您可以从代码内部或从解释器调用它,如下所示:
import cProfile
cProfile.run('foo()')
更有用的是,您可以在运行脚本时调用cProfile:
python -m cProfile myscript.py
为了更简单,我制作了一个名为“profile.bat”的小批处理文件:
python -m cProfile %1
所以我要做的就是跑:
profile euler048.py
我得到了这个:
1007 function calls in 0.061 CPU seconds
Ordered by: standard name
ncalls tottime percall cumtime percall filename:lineno(function)
1 0.000 0.000 0.061 0.061 <string>:1(<module>)
1000 0.051 0.000 0.051 0.000 euler048.py:2(<lambda>)
1 0.005 0.005 0.061 0.061 euler048.py:2(<module>)
1 0.000 0.000 0.061 0.061 {execfile}
1 0.002 0.002 0.053 0.053 {map}
1 0.000 0.000 0.000 0.000 {method 'disable' of '_lsprof.Profiler objects}
1 0.000 0.000 0.000 0.000 {range}
1 0.003 0.003 0.003 0.003 {sum}
编辑:更新了2013年PyCon视频资源的链接,标题为Python评测也可以通过YouTube。
cProfile非常适合于分析,而kcachegrind非常适合于可视化结果。中间的pyprov2calltree处理文件转换。
python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree
所需的系统包:
kcachegrind(Linux)、qcachegrind(MacOs)
Ubuntu上的设置:
apt-get install kcachegrind
pip install pyprof2calltree
结果:
@Maxy对这个答案的评论对我帮助很大,我认为它应该得到自己的答案:我已经有了cProfile生成的.pstats文件,我不想用pycallgraph重新运行这些文件,所以我使用了gprof2dot,得到了很好的svgs:
$ sudo apt-get install graphviz
$ git clone https://github.com/jrfonseca/gprof2dot
$ ln -s "$PWD"/gprof2dot/gprof2dot.py ~/bin
$ cd $PROJECT_DIR
$ gprof2dot.py -f pstats profile.pstats | dot -Tsvg -o callgraph.svg
还有BLAM!
它使用点(与pycallgraph使用的相同),因此输出看起来类似。我觉得gprof2dot丢失的信息更少:
根据乔·肖(Joe Shaw)关于多线程代码无法按预期工作的回答,我认为cProfile中的runcall方法只是围绕着已配置的函数调用执行self.enable()和self.disable()调用,因此您可以简单地自己执行,并在对现有代码的干扰最小的情况下使用任何代码。