如何配置 Python 脚本?

欧拉计画和其他编码竞赛经常有最多的运行时间,或者人们吹嘘他们的特定解决方案的运行速度。使用 Python 时,有时这些方法有些繁琐 - 即在__main__添加计时代码。

剖析 Python 程序需要花费多长时间的好方法是什么?

答案

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}

编辑:更新了指向 PyCon 2013 名为Python Profiling的良好视频资源的链接
也通过 YouTube

前一阵子我做了pycallgraph ,它从您的 Python 代码生成了可视化效果。 编辑:我已经更新了该示例以使其可用于本文撰写时的最新版本 3.3。

pip install pycallgraph并安装GraphViz 之后,您可以从命令行运行它:

pycallgraph graphviz -- ./mypythonscript.py

或者,您可以分析代码的特定部分:

from pycallgraph import PyCallGraph
from pycallgraph.output import GraphvizOutput

with PyCallGraph(output=GraphvizOutput()):
    code_to_profile()

这些都将生成一个pycallgraph.png文件,类似于下图:

在此处输入图片说明

值得指出的是,使用探查器仅在主线程上有效(默认情况下),如果使用其他线程,则不会从其他线程获得任何信息。这可能有点麻烦,因为在探查器文档中完全没有提及。

如果您还想分析线程,则需要查看文档中的threading.setprofile()函数

您也可以创建自己的threading.Thread子类来做到这一点:

class ProfiledThread(threading.Thread):
    # Overrides threading.Thread.run()
    def run(self):
        profiler = cProfile.Profile()
        try:
            return profiler.runcall(threading.Thread.run, self)
        finally:
            profiler.dump_stats('myprofile-%d.profile' % (self.ident,))

并使用该ProfiledThread类而不是标准类。它可能会给您带来更大的灵活性,但是我不确定是否值得,特别是如果您使用的是不使用您的类的第三方代码。

python Wiki 是用于分析资源的好页面: http : //wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code

就像 python docs 一样: http : //docs.python.org/library/profile.html

如 Chris Lawlor 所示,cProfile 是一个很棒的工具,可以轻松地用于打印到屏幕上:

python -m cProfile -s time mine.py <args>

或提交:

python -m cProfile -o output.file mine.py <args>

PS > 如果您使用的是 Ubuntu,请确保安装 python-profile

sudo apt-get install python-profiler

如果输出到文件,则可以使用以下工具获得不错的可视化效果

PyCallGraph:创建调用图图像的工具
安装:

sudo pip install pycallgraph

跑:

pycallgraph mine.py args

视图:

gimp pycallgraph.png

您可以使用任何喜欢的方式查看 png 文件,我使用过 gimp
不幸的是我经常得到

点:对于 cairo-renderer 位图,图形太大。按 0.257079 缩放以适应

这使我的图像变小了。所以我通常创建 svg 文件:

pycallgraph -f svg -o pycallgraph.svg mine.py <args>

PS > 确保安装 graphviz(提供点程序):

sudo pip install graphviz

通过 @maxy / @quodlibetor 使用 gprof2dot 进行替代绘图:

sudo pip install gprof2dot
python -m cProfile -o profile.pstats mine.py
gprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg

@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

和布莱姆!

它使用点(pycallgraph 使用相同的东西),因此输出看起来类似。我的印象是,尽管 gprof2dot 丢失的信息更少:

gprof2dot示例输出

在研究此主题时,我遇到了一个名为SnakeViz的便捷工具。 SnakeViz 是基于 Web 的配置文件可视化工具。这是非常容易安装和使用。我使用它的通常方法是使用%prun生成一个统计文件,然后在 SnakeViz 中进行分析。

所使用的主要可视化技术是如下所示的森伯斯特图 ,其中,函数调用的层次结构被安排为弧形层,并且时间信息以其角度宽度编码。

最好的事情是您可以与图表进行交互。例如,要放大,可以单击圆弧,然后将圆弧及其后代放大为新的旭日形以显示更多详细信息。

在此处输入图片说明

我认为cProfile非常适合分析,而kcachegrind非常适合可视化结果。 pyprof2calltree之间的pyprof2calltree处理文件转换。

python -m cProfile -o script.profile script.py
pyprof2calltree -i script.profile -o script.calltree
kcachegrind script.calltree

要安装所需的工具(至少在 Ubuntu 上):

apt-get install kcachegrind
pip install pyprof2calltree

结果:

结果截图

找到所有时间的最简单 最快的方法。

1. pip install snakeviz

2. python -m cProfile -o temp.dat <PROGRAM>.py

3. snakeviz temp.dat

在浏览器中绘制饼图。最大的一块是问题功能。很简单的。

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

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

还想指出,OP 表示 “概要分析”,但看来他的意思是 “定时”。请记住,配置文件后,程序运行速度会变慢。

在此处输入图片说明

一个不错的分析模块是 line_profiler(使用脚本 kernprof.py 调用)。可以在这里下载。

我的理解是 cProfile 仅提供有关每个功能花费的总时间的信息。因此,单独的代码行不会计时。这是科学计算中的一个问题,因为单行通常会花费很多时间。另外,正如我记得的那样,cProfile 并没有抓住我花在 numpy.dot 上的时间。