Project Euler和其他编码竞赛通常有最长的运行时间,或者人们吹嘘他们的特定解决方案运行速度有多快。对于Python,有时方法有些笨拙——即向__main__添加计时代码。

描述Python程序运行时间的好方法是什么?


当前回答

有很多很好的答案,但它们要么使用命令行,要么使用一些外部程序来分析和/或排序结果。

我真的错过了在IDE(eclipsePyDev)中使用而不接触命令行或安装任何东西的方法。所以就在这里。

无命令行分析

def count():
    from math import sqrt
    for x in range(10**5):
        sqrt(x)

if __name__ == '__main__':
    import cProfile, pstats
    cProfile.run("count()", "{}.profile".format(__file__))
    s = pstats.Stats("{}.profile".format(__file__))
    s.strip_dirs()
    s.sort_stats("time").print_stats(10)

有关更多信息,请参阅文档或其他答案。

其他回答

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。

根据乔·肖(Joe Shaw)关于多线程代码无法按预期工作的回答,我认为cProfile中的runcall方法只是围绕着已配置的函数调用执行self.enable()和self.disable()调用,因此您可以简单地自己执行,并在对现有代码的干扰最小的情况下使用任何代码。

@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丢失的信息更少:

当我不是服务器的根用户时,我使用lsprofcalltree.py并像这样运行我的程序:

python lsprofcalltree.py -o callgrind.1 test.py

然后我可以用任何callgrind兼容的软件打开报告,比如qcachegrind

还值得一提的是GUI cProfile转储查看器RunSnakeRun。它允许您排序和选择,从而放大程序的相关部分。图片中矩形的大小与所用时间成正比。如果您将鼠标悬停在一个矩形上,它将突出显示表中的调用以及地图上的任何位置。双击矩形时,它会放大该部分。它将显示谁调用了该部分以及该部分调用了什么。

描述性信息非常有用。它向您显示了该位的代码,当您处理内置库调用时,该代码会很有用。它告诉要查找代码的文件和行。

还想指出,OP说的是“剖析”,但似乎他是指“时机”。请记住,程序在评测时运行速度会变慢。