如何分析 Python 脚本?
-
06-09-2019 - |
题
欧拉项目和其他编码竞赛通常有最长运行时间,或者人们吹嘘他们特定解决方案的运行速度。对于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}
编辑:从2013 PYCON更新链接到一个良好的视频资源标题 的 的Python仿形 强> 结果 另外rel="noreferrer">。
其他提示
前一段予制成 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
类,而不是标准的一个。它可能会给你更多的灵活性,但我不知道它是值得的,特别是如果你使用的是这不会使用你的类的第三方代码。
在蟒蛇Wiki是用于剖析资源造成很大的页面: http://wiki.python.org/moin/PythonSpeed/PerformanceTips#Profiling_Code
由于是python文档: http://docs.python.org/library/profile.html
如图克里斯劳勒CPROFILE是一个伟大的工具,并且可以容易地用于打印到屏幕:
python -m cProfile -s time mine.py <args>
或到文件:
python -m cProfile -o output.file mine.py <args>
PS>如果您使用Ubuntu,请确保安装python-轮廓
sudo apt-get install python-profiler
如果您输出到文件,您可以使用以下工具得到很好的可视化
PyCallGraph:创建调用图的图像,点击一个工具 安装:结果
sudo pip install pycallgraph
运行:
pycallgraph mine.py args
视图:
gimp pycallgraph.png
你可以使用任何你想观看PNG文件,我用GIMP 的结果 不幸的是我经常收到
点:曲线图是用于开罗-渲染位图太大。通过0.257079缩放以适合
这使得我的图片unusably小。所以我一般创建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
@美星对这个答案帮了我,以至于我认为它值得自己的答案:我已经有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虽然失去信息少的印象:
我跑进称为一个方便的工具 SnakeViz研究这个话题时。 SnakeViz是一个基于Web的分析可视化工具。它的安装和使用非常方便。我用它的通常的方法是生成具有%prun
一个统计文件,然后执行分析在SnakeViz。
所使用的主要技术即是的旭日图表强>如下所示,其中的功能层次调用被布置为在它们的角宽度编码弧和时间信息的层。
最好的事情是你可以用图表进行交互。例如,为了在一个放大可以点击的电弧,电弧及其后代将被放大为一个新的旭日以显示更多的信息。
我觉得 cProfile
非常适合分析,同时 kcachegrind
非常适合可视化结果。这 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
结果:
另外值得一提的是GUI CPROFILE转储观察者 RunSnakeRun 。它可以让你排序和选择,从而放大对方案的相关部分。画面中的矩形的尺寸是成比例的时间。如果将鼠标放在一个长方形它强调在表中无处不在地图上的这个电话。当你在一个矩形双击放大了的部分。它会告诉你谁调用部分和部分所说的。
在描述信息是非常有用的。这表明你对于该位的代码时,你是在处理内置库调用它可以是有帮助的。它告诉你什么文件,什么网上找的代码。
而且要在该OP所述“剖析”指向但它似乎他的意思“定时”。请记住程序运行速度会变慢异形时。
最简单并找到最快的方式,所有的时间是怎么回事。
1. pip install snakeviz
2. python -m cProfile -o temp.dat <PROGRAM>.py
3. snakeviz temp.dat
绘制在浏览器中的饼图。最大的一块是问题的功能。很简单。
一个很好的分析模块是line_profiler(使用脚本kernprof.py调用)。它可以在这里下载 。
我理解的是仅CPROFILE给出关于在每个功能花费的总时间的信息。的代码,使各行不定时。这是在科学计算问题,因为往往一个单行可以采取大量的时间。另外,我记得,CPROFILE没赶上,我几乎花光中说numpy.dot的时间。
我最近创建金枪鱼用于可视化Python运行时和进口型材;这可能是有帮助这里。
用安装
pip3 install tuna
创建运行时配置文件
python -mcProfile -o program.prof yourfile.py
或导入配置文件(Python的3.7+必需)
python -X importprofile yourfile.py 2> import.log
然后,只需对文件运行金枪鱼
tuna program.prof
有很多伟大的答案,但它们要么使用命令行或用于分析和/或分选的结果的一些外部程序。
我确实错过了一些方法,我可以在我的IDE(Eclipse的PyDev的),而不触及命令行或安装任何东西使用。所以这里。
剖析不带命令行
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)
请参阅文档或其他的答案为更多的信息。
继乔·肖的关于多线程代码没有按预期工作的答案,我想,在CPROFILE的runcall
方法仅仅是做围绕异形函数调用self.enable()
和self.disable()
调用,因此你可以简单地做自己,有任何代码你想在两者之间具有与现有代码的干扰最小。
在Virtaal的源有一个非常有用的类和装饰,可以使配置文件(甚至具体方法/功能)很容易。输出然后可以在KCacheGrind非常舒适地观看。
CPROFILE是伟大的快速分析,但大部分是为我错误结束的时间。功能runctx通过正确初始化环境和变量解决了这个问题,希望它是有用的人:
import cProfile
cProfile.runctx('foo()', None, locals())
我的方法是使用yappi( https://code.google.com/p/yappi/ ) 。这是特别有用的结合,其中(甚至只是为了调试)您注册方法启动,停止和打印分析信息,如RPC服务器以这种方式:
@staticmethod
def startProfiler():
yappi.start()
@staticmethod
def stopProfiler():
yappi.stop()
@staticmethod
def printProfiler():
stats = yappi.get_stats(yappi.SORTTYPE_TTOT, yappi.SORTORDER_DESC, 20)
statPrint = '\n'
namesArr = [len(str(stat[0])) for stat in stats.func_stats]
log.debug("namesArr %s", str(namesArr))
maxNameLen = max(namesArr)
log.debug("maxNameLen: %s", maxNameLen)
for stat in stats.func_stats:
nameAppendSpaces = [' ' for i in range(maxNameLen - len(stat[0]))]
log.debug('nameAppendSpaces: %s', nameAppendSpaces)
blankSpace = ''
for space in nameAppendSpaces:
blankSpace += space
log.debug("adding spaces: %s", len(nameAppendSpaces))
statPrint = statPrint + str(stat[0]) + blankSpace + " " + str(stat[1]).ljust(8) + "\t" + str(
round(stat[2], 2)).ljust(8 - len(str(stat[2]))) + "\t" + str(round(stat[3], 2)) + "\n"
log.log(1000, "\nname" + ''.ljust(maxNameLen - 4) + " ncall \tttot \ttsub")
log.log(1000, statPrint)
然后当你的程序工作,你可以通过调用startProfiler
RPC方法随时开始探查和转储通过调用printProfiler
剖析信息的日志文件(或修改RPC方法将其返回给调用者),并得到这样的输出:
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
name ncall ttot tsub
2014-02-19 16:32:24,128-|SVR-MAIN |-(Thread-3 )-Level 1000:
C:\Python27\lib\sched.py.run:80 22 0.11 0.05
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515 22 0.11 0.0
M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66 1 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.date_time_string:464 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py._get_raw_meminfo:243 4 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\_psmswindows.py.get_system_cpu_times:148 4 0.0 0.0
<string>.__new__:8 220 0.0 0.0
C:\Python27\lib\socket.py.close:276 4 0.0 0.0
C:\Python27\lib\threading.py.__init__:558 1 0.0 0.0
<string>.__new__:8 4 0.0 0.0
C:\Python27\lib\threading.py.notify:372 1 0.0 0.0
C:\Python27\lib\rfc822.py.getheader:285 4 0.0 0.0
C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301 1 0.0 0.0
C:\Python27\lib\xmlrpclib.py.end:816 3 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467 1 0.0 0.0
C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460 1 0.0 0.0
C:\Python27\lib\SocketServer.py.close_request:475 1 0.0 0.0
c:\users\zasiec~1\appdata\local\temp\easy_install-hwcsr1\psutil-1.1.2-py2.7-win32.egg.tmp\psutil\__init__.py.cpu_times:1066 4 0.0 0.0
有可能不是短脚本非常有用,但有助于优化服务器类工艺尤其是考虑到printProfiler
方法可以称为随时间多次来分析和比较例如不同程序的使用场景。
曾经想知道Python脚本是做什么是地狱?输入 检查外壳。检查壳牌可打印/改变全局和运行 功能,而无需中断正在运行的脚本。现在,随着 自动完成和命令历史(仅在Linux)。
检查壳牌不是PDB式调试器。
https://github.com/amoffat/Inspect-Shell
您可以使用(和你的手表)。
要添加到 https://stackoverflow.com/a/582337/1070617 ,
我撰写本单元,它允许您使用CPROFILE和轻松地查看它的输出。更这里: https://github.com/ymichael/cprofilev
$ python -m cprofilev /your/python/program
# Go to http://localhost:4000 to view collected statistics.
另请参见: http://ymichael.com/ 2014/03/08 /纹-蟒与 - cprofile.html 关于如何使所收集的统计意义。
PyVmMonitor 是一个在 Python 中处理分析的新工具: http://www.pyvmonitor.com/
它有一些独特的功能,例如
- 将探查器附加到正在运行的 (CPython) 程序
- 通过 Yappi 集成进行按需分析
- 在不同的机器上配置文件
- 多进程支持(多处理、django...)
- 实时采样/CPU 视图(带时间范围选择)
- 通过 cProfile/profile 集成进行确定性分析
- 分析现有 PStats 结果
- 打开DOT文件
- 编程式 API 访问
- 按方法或系列对样品进行分组
- PyDev 集成
- PyCharm 集成
笔记:它是商业的,但免费开源。
这将取决于你想要看的出来分析一下。简单的时间 度量可以通过(bash)的给予。
time python python_prog.py
即使 '的/ usr /斌/时间' 可以输出通过使用 '--verbose' 标志详细的指标。
要查看各项功能给定的时间度量,并更好地了解有多少时间花在功能,你可以在Python中使用内置的CPROFILE。
走进像性能更详细的指标,时间不是唯一的度量。你可以不用担心内存,线程等结果 分析选项:点击 1.的 line_profiler 强>是通常用于找出计时度量线由行另一分析器。结果 2.的 memory_profiler 强>是配置内存使用的工具。结果 3.的 heapy(从项目顾比)个人资料如何在堆中的对象被使用。
这些都是一些常见的我倾向于使用的。但是,如果你想了解更多信息,请阅读这篇书 这是一个相当不错的本子上记的表现开始了。您可以使用用Cython和JIT(刚刚在时间)汇编的蟒蛇移动到高级的主题。
有也称为统计分析器 statprof
。这是一个采样分析器,所以它增加了最小的开销到您的代码和基于行的(基于函数的不只是)时间安排。它更适合喜欢游戏的软实时应用,但可能具有较低的精度比CPROFILE。
在的PyPI 的版本是有点陈旧,因此可以通过与pip
安装它指定 git仓库:
pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01
您可以像这样运行:
import statprof
with statprof.profile():
my_questionable_function()
当我不是根在服务器上,我使用 lsprofcalltree.py 和运行我的程序是这样的:
python lsprofcalltree.py -o callgrind.1 test.py
然后,我可以与任何callgrind兼容的软件打开该报告,如 qcachegrind
<强> gprof2dot_magic 强>
有gprof2dot
来分析任何的Python语句作为在JupyterLab或Jupyter笔记本一个DOT图表魔术功能。
GitHub库: https://github.com/mattijn/gprof2dot_magic
<强>安装强>
请确保你已经在Python包gprof2dot_magic
。
pip install gprof2dot_magic
它的依赖gprof2dot
和graphviz
将安装以及
<强>使用强>
要启用的神奇功能,首先加载gprof2dot_magic
模块
%load_ext gprof2dot_magic
和然后轮廓线的任何语句作为DOT图作为这样:
%gprof2dot print('hello world')
在终端只(和简单的)解决方案,如果所有那些花哨UI的安装失败或运行:结果
完全忽视cProfile
并用pyinstrument
取代它,将收集和执行后右显示呼叫的树
安装:
$ pip install pyinstrument
资料和显示结果:
$ python -m pyinstrument ./prog.py
与python2和3工作。