如何配置Python脚本?


1282

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

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


112
项目Euler程序不需要配置文件。您有一种算法可以在一分钟内完成工作,或者您有完全错误的算法。“调整”很少是合适的。通常,您必须采用全新的方法。
S.Lott

105
S.Lott:分析通常是确定哪些子例程缓慢的有用方法。花费很长时间的子例程非常适合用于算法改进。
stalepretzel 2012年

Answers:


1369

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
Also via YouTube


251
对结果进行排序也很有用,可以通过-s开关来完成,例如:“-s time”。您可以使用累积/名称/时间/文件排序选项。
吉里(Jiri)2009年

19
还值得注意的是,您可以使用魔术函数%prun(配置文件运行)从ipython使用cProfile模块。首先导入您的模块,然后使用%prun调用主函数:import euler048; %prun euler048.main()
RussellStewart 2014年

53
为了可视化cProfile转储(由创建python -m cProfile -o <out.profile> <script>),RunSnakeRun的调用runsnake <out.profile>非常有价值。
莉莉·钟

13
@NeilG甚至蟒蛇3,cprofile仍建议profile
trichoplax

17
为了可视化cProfile转储,RunSnakeRun自2011年以来未进行更新,并且不支持python3。您应该使用snakeviz代替
贾科莫Tecya Pigani

423

前一阵子,我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类似于下图的文件:

在此处输入图片说明


43
您是否根据通话量进行着色?如果是这样,您应该基于时间进行着色,因为调用次数最多的函数并不总是花费时间最多的函数。
红色

21
@red您可以根据自己的喜好自定义颜色,甚至每次测量都可以自定义颜色。例如,红色代表通话,蓝色代表时间,绿色代表内存使用情况。
gak 2013年

2
收到此错误Traceback (most recent call last): /pycallgraph.py", line 90, in generate output.done() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 94, in done source = self.generate() File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 143, in generate indent_join.join(self.generate_attributes()), File "/net_downloaded/pycallgraph-develop/pycallgraph/output/graphviz.py", line 169, in generate_attributes section, self.attrs_from_dict(attrs), ValueError: zero length field name in format
Ciasto piekarz 2014年

3
我对此进行了更新,以提及您需要安装GraphViz才能使它按所述方式工作。在Ubuntu上,这只是sudo apt-get install graphviz
mlissner

2
这需要一点工作来安装,这里有3个步骤可以帮助您。1.通过pip安装,2.通过exe安装GraphViz。3.将路径变量设置为GraphViz目录。4.了解如何解决所有其他错误。5.找出将png文件保存在哪里?
沼泽

199

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

如果您还想分析线程,则需要查看文档中的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该类而不是标准类。它可能会给您带来更大的灵活性,但是我不确定是否值得,特别是如果您使用的是不使用您的类的第三方代码。


1
我也没有在文档中看到对runcall的任何引用。看一下cProfile.py,我不确定为什么要使用threading.Thread.run函数或self作为参数。我期望在这里看到对另一个线程的run方法的引用。
PypeBros 2011年

它不在文档中,但在模块中。参见hg.python.org/cpython/file/6bf07db23445/Lib/cProfile.py#l140。这使您可以分析特定的函数调用,在我们的例子中,我们要分析线程的target函数,这是threading.Thread.run()调用执行的内容。但是正如我在回答中所说,子类Thread可能不值得,因为任何第三方代码都不会使用它,而是使用threading.setprofile()
Joe Shaw

9
用profiler.enable()和profiler.disable()包装代码似乎也很好。基本上,这就是runcall所做的,并且不执行任何数量的参数或类似的事情。
PypeBros 2011年


1
Joe,您知道探查器在Python 3.4中如何与asyncio一起玩吗?
Nick Chammas 2015年

148

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

apt-get install python-profiler 

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

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

 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(提供点程序):

pip install graphviz

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

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

12
gprof2dot也可以做那些图。我认为输出会更好(示例)。
maxy 2012年

2
如果您使用的是OSX,还需要graphviz
Vaibhav Mishra 2014年

134

@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示例输出


1
好的方法,效果很好,因为您可以在Chrome等中查看SVG并将其放大/缩小。第三行有错字,应该是:ln -s pwd/gprof2dot/gprof2dot.py $ HOME / bin(或在大多数外壳中使用ln -s $ PWD / gprof2dot / gprof2dot.py〜/ bin-严重的重音首先被视为格式版)。
RichVel 2013年

2
啊,好点。我ln几乎每次都错误地提出论据顺序。
quodlibetor

7
诀窍是要记住ln和cp具有相同的参数顺序-将其视为“将file1复制到file2或dir2,但建立链接”
RichVel 2013年

这是有道理的,我认为在联机帮助页中使用“ TARGET”会让我大跌眼镜。
quodlibetor

拜托,你是怎么变成圆角的?我觉得它提高了可读性。我只是看到丑陋的尖角,这在盒子周围有许多边缘的情况下并不酷。
Hibou57 2014年

77

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

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

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

在此处输入图片说明


1
CodeCabbie的答案包括(简短的)安装说明,并显示如何(轻松)使用SnakeViz。
奥伦·米尔曼

在这里,我已经阅读了恕我直言很好的指南,如何在jupyter笔记本上使用Python进行概要分析:向datadata.com/speed-up-jupyter-notebooks-20716cbe2025
Alexei Martianov

72

最简单最快的方式找到所有的时间是怎么回事。

1. pip install snakeviz

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

3. snakeviz temp.dat

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


1
这非常有帮助。谢谢。
jippyjoe4

55

我认为这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

结果:

结果截图


9
Mac用户安装brew install qcachegrindkcachegrind 使用qcachegrind 说明中的每个配置进行升级,以成功进行性能分析。
凯文·卡兹克

我必须这样做才能使其正常工作:export QT_X11_NO_MITSHM=1
Yonatan Simson

41

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

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

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

在此处输入图片说明


34

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

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


34

我最近创建了金枪鱼,用于可视化Python运行时和导入配置文件。这可能会有所帮助。

在此处输入图片说明

用安装

pip install tuna

创建运行时配置文件

python3 -m cProfile -o program.prof yourfile.py

或导入配置文件(需要Python 3.7+)

python3 -X importprofile yourfile.py 2> import.log

然后在文件上运行金枪鱼

tuna program.prof

33

pprofile

line_profiler(已在此处展示)也受到了启发 pprofile,它被描述为:

线粒度,线程感知的确定性和统计纯Python探查器

它提供的行粒度为line_profiler,它是纯Python,可以用作独立命令或模块,甚至可以生成可以使用轻松分析的callgrind格式文件[k|q]cachegrind

vprof

还有vprof,一个Python包,描述为:

为各种Python程序特征(例如运行时间和内存使用情况)提供丰富的交互式可视化。

热图


14

有很多不错的答案,但是他们要么使用命令行,要么使用某些外部程序来对结果进行概要分析和/或排序。

我真的很想念我可以在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)

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


例如,配置文件打印{map}或{xxx}。我怎么知道从哪个文件调用方法{xxx}?我的个人资料打印{zlib.Compress对象的“方法”的压缩}花费了大部分时间,但是我没有使用任何zlib,因此我猜有些numpy函数可能会使用它。我怎么知道确切的文件和行需要很多时间?
machen

12

在Joe Shaw回答了多线程代码无法按预期工作的回答之后,我发现runcallcProfile 中的方法只是在做,self.enable()并且self.disable()在配置函数调用周围进行调用,因此您可以自己进行操作,并在中间使用任何想要的代码对现有代码的干扰最小。


3
很棒的提示!快速浏览一下cprofile.py的源代码,就会发现它确实这样runcall()做的。更具体地说,在使用创建了Profile实例之后prof = cprofile.Profile(),立即调用prof.disable(),然后在要分析的代码部分周围添加prof.enable()prof.disable()调用。
martineau 2012年

这非常有帮助,但是似乎未分析启用和禁用之间的代码,仅分析了其调用的功能。我有这个权利吗?我必须将该代码包装在一个函数调用中,以使其计入print_stats()中的任何数字。
鲍勃·斯坦

10

在Virtaal的资料中,有一个非常有用的类和装饰器,可以使分析(即使对于特定的方法/函数)也非常容易。然后可以在KCacheGrind中非常舒适地查看输出。


1
谢谢你的帮助。仅供参考:可以与任何代码一起用作独立模块,不需要Virtaal代码库。只需将文件保存到profiling.py并导入profile_func()。使用@profile_func()作为您需要剖析和中提琴的任何功能的装饰器。:)
Amjith '10

9

cProfile非常适合快速分析,但是大多数情况下它以错误结束。函数runctx通过正确初始化环境和变量来解决此问题,希望它对某人有用:

import cProfile
cProfile.runctx('foo()', None, locals())

7

如果要制作累积分析器,则意味着连续运行该函数几次,并观察结果的总和。

您可以使用以下cumulative_profiler装饰器:

它是特定于python> = 3.6的python,但是您可以删除nonlocal它,以便在较旧版本上运行。

import cProfile, pstats

class _ProfileFunc:
    def __init__(self, func, sort_stats_by):
        self.func =  func
        self.profile_runs = []
        self.sort_stats_by = sort_stats_by

    def __call__(self, *args, **kwargs):
        pr = cProfile.Profile()
        pr.enable()  # this is the profiling section
        retval = self.func(*args, **kwargs)
        pr.disable()

        self.profile_runs.append(pr)
        ps = pstats.Stats(*self.profile_runs).sort_stats(self.sort_stats_by)
        return retval, ps

def cumulative_profiler(amount_of_times, sort_stats_by='time'):
    def real_decorator(function):
        def wrapper(*args, **kwargs):
            nonlocal function, amount_of_times, sort_stats_by  # for python 2.x remove this row

            profiled_func = _ProfileFunc(function, sort_stats_by)
            for i in range(amount_of_times):
                retval, ps = profiled_func(*args, **kwargs)
            ps.print_stats()
            return retval  # returns the results of the function
        return wrapper

    if callable(amount_of_times):  # incase you don't want to specify the amount of times
        func = amount_of_times  # amount_of_times is the function in here
        amount_of_times = 5  # the default amount
        return real_decorator(func)
    return real_decorator

分析功能 baz

import time

@cumulative_profiler
def baz():
    time.sleep(1)
    time.sleep(2)
    return 1

baz()

baz 跑了5次并打印了这个:

         20 function calls in 15.003 seconds

   Ordered by: internal time

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
       10   15.003    1.500   15.003    1.500 {built-in method time.sleep}
        5    0.000    0.000   15.003    3.001 <ipython-input-9-c89afe010372>:3(baz)
        5    0.000    0.000    0.000    0.000 {method 'disable' of '_lsprof.Profiler' objects}

指定次数

@cumulative_profiler(3)
def baz():
    ...

7

仅终端机(也是最简单的)解决方案,如果所有这些精美的UI无法安装或运行:完全
忽略cProfile并替换为pyinstrument,它将在执行后立即收集并显示调用树。

安装:

$ pip install pyinstrument

配置文件和显示结果:

$ python -m pyinstrument ./prog.py

适用于python2和3。

[编辑]仅用于分析部分代码的API文档可在此处找到。


6

我的方式是使用yappi(https://github.com/sumerc/yappi)。与RPC服务器结合使用时特别有用,在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)

然后,当程序工作时,您可以随时通过调用startProfilerRPC方法来启动事件探查器,并通过调用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方法可以随时间多次调用以概要分析和比较例如不同的程序使用情况时,尤其如此。

在较新版本的yappi中,以下代码将起作用:

@staticmethod
def printProfile():
    yappi.get_func_stats().print_all()

它不应该命名为Stupendous Yappi吗?
Therealstubot 2014年

不幸的是,上面的代码仅适用于pypy上没有的0.62版本。该模块需要从此处的0.62来源进行编译:github.com/nirs/yappi/releases或使用我为回购创建的用于Windows的构建为此目的
Girgitt先生18年

通过修改printProfiler函数,可以很容易地提供与1.0版的兼容性-至少对于打印输出而言- def printProfiler(): if not yappi_available: return stats = yappi.get_func_stats() stats.print_all(columns={0:("name",90), 1:("ncall", 5), 2:("tsub", 8), 3:("ttot", 8), 4:("tavg",8)}) (尝试几次后将代码块插入我放弃的注释中就可以了。对于面向编程的问答网站,这很难做到。 )
Girgitt先生19年

4

PyVmMonitor是处理Python中性能分析的新工具:http ://www.pyvmmonitor.com/

它具有一些独特的功能,例如

  • 将探查器附加到正在运行的(CPython)程序
  • 通过Yappi集成进行按需配置
  • 在其他计算机上配置文件
  • 多进程支持(多处理,django ...)
  • 实时采样/ CPU视图(具有时间范围选择)
  • 通过cProfile / profile集成进行确定性分析
  • 分析现有的PStats结果
  • 打开DOT文件
  • 程序化API访问
  • 按方法或行对样本进行分组
  • PyDev集成
  • PyCharm整合

注意:它是商业性的,但对开源免费。


4

gprof2dot_magic

魔术函数,用于gprof2dot在JupyterLab或Jupyter Notebook中将任何Python语句配置为DOT图。

在此处输入图片说明

GitHub回购:https : //github.com/mattijn/gprof2dot_magic

安装

确保您拥有Python软件包gprof2dot_magic

pip install gprof2dot_magic

它的依赖关系gprof2dotgraphviz也将被安装

用法

要启用魔术功能,请先加载gprof2dot_magic模块

%load_ext gprof2dot_magic

然后将任何行语句配置为DOT图,如下所示:

%gprof2dot print('hello world')

在此处输入图片说明


3

是否曾经想知道python脚本到底在做什么?输入检查外壳。通过Inspect Shell,您可以在不中断正在运行的脚本的情况下打印/更改全局变量并运行函数。现在具有自动完成和命令历史记录(仅在Linux上)。

Inspect Shell不是pdb样式的调试器。

https://github.com/amoffat/Inspect-Shell

您可以使用它(和您的手表)。



3

这将取决于您希望从分析中看到什么。可以通过(bash)给出简单的时间指标。

time python python_prog.py

甚至'/ usr / bin / time'也可以使用'--verbose'标志输出详细的指标。

要检查每个函数给出的时间指标并更好地了解在函数上花费了多少时间,可以在python中使用内置的cProfile。

进入性能,时间等更详细的指标并不是唯一的指标。您可以担心内存,线程等问题。
分析选项:
1. line_profiler是另一个分析器,通常用于逐行找出时序度量。
2. memory_profiler是用于分析内存使用情况的工具。
3. 堆(来自项目Guppy)描述如何使用堆中的对象。

这些是我倾向于使用的一些常见的东西。但是,如果您想了解更多信息,请尝试阅读本书。 这是一本关于性能入门的不错的书。您可以转到使用Cython和JIT(即时)编译的python的高级主题。


2

使用austin之类的统计分析器,不需要任何检测,这意味着您可以轻松地从Python应用程序中分析数据

austin python3 my_script.py

原始输出不是很有用,但是您可以将其通过管道传递到flamegraph.pl 以获取该数据的火焰图表示,从而可以细分所花费的时间(以毫秒为单位的实时时间)。

austin python3 my_script.py | flamegraph.pl > my_script_profile.svg

1

还有一个名为的统计分析器statprof。它是一个采样探查器,因此它为您的代码增加了最小的开销,并提供了基于行(不仅仅基于函数)的时序。它更适合诸如游戏之类的软实时应用程序,但精度可能不如cProfile。

pypi中版本有点旧,因此可以pip通过指定git仓库来安装它:

pip install git+git://github.com/bos/statprof.py@1a33eba91899afe17a8b752c6dfdec6f05dd0c01

您可以像这样运行它:

import statprof

with statprof.profile():
    my_questionable_function()

另请参阅https://stackoverflow.com/a/10333592/320036


1

我刚刚从pypref_time中开发了自己的探查器:

https://github.com/modaresimr/auto_profiler

通过添加装饰器,它将显示一棵耗时的功能树

@Profiler(depth=4, on_disable=show)

Install by: pip install auto_profiler

import time # line number 1
import random

from auto_profiler import Profiler, Tree

def f1():
    mysleep(.6+random.random())

def mysleep(t):
    time.sleep(t)

def fact(i):
    f1()
    if(i==1):
        return 1
    return i*fact(i-1)


def show(p):
    print('Time   [Hits * PerHit] Function name [Called from] [Function Location]\n'+\
          '-----------------------------------------------------------------------')
    print(Tree(p.root, threshold=0.5))

@Profiler(depth=4, on_disable=show)
def main():
    for i in range(5):
        f1()

    fact(3)


if __name__ == '__main__':
    main()

示例输出


Time   [Hits * PerHit] Function name [Called from] [function location]
-----------------------------------------------------------------------
8.974s [1 * 8.974]  main  [auto-profiler/profiler.py:267]  [/test/t2.py:30]
├── 5.954s [5 * 1.191]  f1  [/test/t2.py:34]  [/test/t2.py:14]
   └── 5.954s [5 * 1.191]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
       └── 5.954s [5 * 1.191]  <time.sleep>
|
|
|   # The rest is for the example recursive function call fact
└── 3.020s [1 * 3.020]  fact  [/test/t2.py:36]  [/test/t2.py:20]
    ├── 0.849s [1 * 0.849]  f1  [/test/t2.py:21]  [/test/t2.py:14]
       └── 0.849s [1 * 0.849]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
           └── 0.849s [1 * 0.849]  <time.sleep>
    └── 2.171s [1 * 2.171]  fact  [/test/t2.py:24]  [/test/t2.py:20]
        ├── 1.552s [1 * 1.552]  f1  [/test/t2.py:21]  [/test/t2.py:14]
           └── 1.552s [1 * 1.552]  mysleep  [/test/t2.py:15]  [/test/t2.py:17]
        └── 0.619s [1 * 0.619]  fact  [/test/t2.py:24]  [/test/t2.py:20]
            └── 0.619s [1 * 0.619]  f1  [/test/t2.py:21]  [/test/t2.py:14]


0

用于在IPython笔记本上快速获取代码段的配置文件统计信息。可以将line_profiler和memory_profiler直接嵌入他们的笔记本中。

得到它!

!pip install line_profiler
!pip install memory_profiler

加载它!

%load_ext line_profiler
%load_ext memory_profiler

用它!


%时间

%time print('Outputs CPU time,Wall Clock time') 
#CPU times: user 2 µs, sys: 0 ns, total: 2 µs Wall time: 5.96 µs

给出:

  • CPU时间:CPU级执行时间
  • 系统时间:系统级执行时间
  • 总计:CPU时间+系统时间
  • 挂钟时间:挂钟时间

%timeit

%timeit -r 7 -n 1000 print('Outputs execution time of the snippet') 
#1000 loops, best of 7: 7.46 ns per loop
  • 在循环(n)次中,在给定的运行次数(r)中给出最佳时间。
  • 输出有关系统缓存的详细信息:
    • 当代码片段多次执行时,系统会缓存一些操作,而不会再次执行它们,这可能会影响概要文件报告的准确性。

%修剪

%prun -s cumulative 'Code to profile' 

给出:

  • 函数调用数(ncalls)
  • 每个函数调用都有条目(不同)
  • 每次通话所花费的时间(每次通话)
  • 直到该函数调用为止的时间(cumtime)
  • 称为etc的func /模块的名称...

累积资料


%mit

%memit 'Code to profile'
#peak memory: 199.45 MiB, increment: 0.00 MiB

给出:

  • 内存使用情况

%lprun

#Example function
def fun():
  for i in range(10):
    print(i)

#Usage: %lprun <name_of_the_function> function
%lprun -f fun fun()

给出:

  • 逐行统计

LineProfile

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.