如何分析 Python 脚本?

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

分析 Python 程序运行时间的好方法是什么?

756234 次浏览

Python包含一个名为cProfile的分析器。它不仅给出了总运行时间,还单独计算了每个函数的时间,并告诉您每个函数被调用了多少次,从而可以轻松确定应该在哪里进行优化。

您可以从代码中或从解释器中调用它,如下所示:

import cProfilecProfile.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 namencalls  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分析
通过YouTube.

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

值得指出的是,使用分析器仅在主线程上工作(默认情况下),如果你使用它们,你将无法从其他线程获得任何信息。这可能有点麻烦,因为它在分析器留档中完全没有提到。

如果您还想分析线程,您将需要查看文档中的#0函数

你也可以创建自己的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文档一样: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配置文件

apt-get install python-profiler

如果您输出到文件,您可以使用以下工具获得漂亮的可视化效果

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

 pip install pycallgraph

运行:

 pycallgraph mine.py args

观点:

 gimp pycallgraph.png

你可以用任何你喜欢的东西来查看png文件,我用的是gimp
我经常遇到

点:图形太大,不适合cairo-render位图。缩放0.257079以适应

这使得我的图像小得无法使用。所以我通常创建svg文件:

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

PS>确保安装Graphviz(它提供了点程序):

pip install graphviz

通过@maxy/@quodlibetor使用gProph2dot的替代图形:

pip install gprof2dotpython -m cProfile -o profile.pstats mine.pygprof2dot -f pstats profile.pstats | dot -Tsvg -o mine.svg

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

我的理解是cProfile只提供在每个函数上花费的总时间的信息。所以单个代码行没有计时。这是科学计算中的一个问题,因为通常一行可能需要很多时间。此外,我记得,cProfile没有赶上我说的时间numpy.dot.

根据Joe Shaw关于多线程代码不能按预期工作的回答,我认为cProfile中的runcall方法只是围绕分析函数调用执行self.enable()self.disable()调用,因此您可以简单地自己执行此操作,并在两者之间拥有任何您想要的代码,对现有代码的干扰最小。

不久前,我制作了#0,它从您的Python代码生成可视化。编辑:我更新了示例以使用3.3,这是本文撰写时的最新版本。

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

pycallgraph graphviz -- ./mypythonscript.py

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

from pycallgraph import PyCallGraphfrom pycallgraph.output import GraphvizOutput
with PyCallGraph(output=GraphvizOutput()):code_to_profile()

其中任何一个都会生成一个类似于下图的pycallgraph.png文件:

输入图片描述

曾经想知道Python脚本到底在做什么?输入检查Shell。检查Shell允许您打印/更改全局值并运行函数而不会中断正在运行的脚本。现在自动完成和命令历史记录(仅在linux上)。

检查Shell不是pdb风格的调试器。

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

@Maxy对这个答案的评论对我帮助很大,我认为它应该得到自己的答案:我已经有了cProfile生成的. pstats文件,我不想用pyallgraph重新运行东西,所以我使用了gpro2dot,得到了漂亮的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!

它使用点(与pyallgraph使用的相同),因此输出看起来很相似。不过,我得到的印象是gpr2dot丢失的信息较少:

gpro输出示例

我的方法是使用yappi(https://github.com/sumerc/yappi)。它与RPC服务器结合特别有用,在RPC服务器中(即使只是为了调试)您可以注册方法来启动、停止和打印分析信息,例如:

@staticmethoddef startProfiler():yappi.start()
@staticmethoddef stopProfiler():yappi.stop()
@staticmethoddef 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    tsub2014-02-19 16:32:24,128-|SVR-MAIN  |-(Thread-3   )-Level 1000:C:\Python27\lib\sched.py.run:80                                                                                                           22        0.11    0.05M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\xmlRpc.py.iterFnc:293                                                22        0.11    0.0M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\serverMain.py.makeIteration:515                                                    22        0.11    0.0M:\02_documents\_repos\09_aheadRepos\apps\ahdModbusSrv\pyAheadRpcSrv\PicklingXMLRPC.py._dispatch:66                                       1         0.0     0.0C:\Python27\lib\BaseHTTPServer.py.date_time_string:464                                                                                    1         0.0     0.0c:\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.0C:\Python27\lib\SimpleXMLRPCServer.py.decode_request_content:537                                                                          1         0.0     0.0c:\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.0C:\Python27\lib\socket.py.close:276                                                                                                       4         0.0     0.0C:\Python27\lib\threading.py.__init__:558                                                                                                 1         0.0     0.0<string>.__new__:8                                                                                                                        4         0.0     0.0C:\Python27\lib\threading.py.notify:372                                                                                                   1         0.0     0.0C:\Python27\lib\rfc822.py.getheader:285                                                                                                   4         0.0     0.0C:\Python27\lib\BaseHTTPServer.py.handle_one_request:301                                                                                  1         0.0     0.0C:\Python27\lib\xmlrpclib.py.end:816                                                                                                      3         0.0     0.0C:\Python27\lib\SimpleXMLRPCServer.py.do_POST:467                                                                                         1         0.0     0.0C:\Python27\lib\SimpleXMLRPCServer.py.is_rpc_path_valid:460                                                                               1         0.0     0.0C:\Python27\lib\SocketServer.py.close_request:475                                                                                         1         0.0     0.0c:\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中,以下代码将起作用:

@staticmethoddef printProfile():yappi.get_func_stats().print_all()

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

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

还想指出OP说'分析',但似乎他的意思是'时间'。请记住,程序在分析时会运行得更慢。

输入图片描述

pProfile

line_profiler(已经在这里介绍过)也启发了#1,它被描述为:

线颗粒度,线程感知确定性和统计纯python分析器

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

vprof

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

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

热图

添加到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/profiling-python-with-cprofile.html,了解如何理解收集的统计数据。

cProfile非常适合快速分析,但大多数时候它都以错误告终。函数runctx通过正确初始化环境和变量解决了这个问题,希望它对某人有用:

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

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

它有一些独特的功能,如

  • 将分析器附加到正在运行的(CPython)程序
  • 与Yappi集成的按需分析
  • 不同机器上的配置文件
  • 多进程支持(多重处理,django…)
  • 实时采样/CPU视图(带时间范围选择)
  • 通过cProfile/Profile集成进行确定性分析
  • 分析现有PStats结果
  • 打开DOT文件
  • 编程API访问
  • 按方法或线对样品进行分组
  • pydev集成
  • PyCharm集成

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

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

我真的错过了一些可以在我的IDE(eclipse-PyDev)中使用的方法,而无需触摸命令行或安装任何东西。所以在这里。

没有命令行的分析

def count():from math import sqrtfor x in range(10**5):sqrt(x)
if __name__ == '__main__':import cProfile, pstatscProfile.run("count()", "{}.profile".format(__file__))s = pstats.Stats("{}.profile".format(__file__))s.strip_dirs()s.sort_stats("time").print_stats(10)

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

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

pypi版本有点旧,所以可以通过指定的git存储库pip安装它:

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

你可以像这样运行它:

import statprof
with statprof.profile():my_questionable_function()

另见https://stackoverflow.com/a/10333592/320036

#0非常适合分析,而#1非常适合可视化结果。中间的#2处理文件转换。

python -m cProfile -o script.profile script.pypyprof2calltree -i script.profile -o script.calltreekcachegrind script.calltree

所需的系统包:

  • kcachegrind(Linux),qcachegrind(MacO)

在Ubuntu上设置:

apt-get install kcachegrindpip install pyprof2calltree

结果:

结果截图

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

使用的主要技术是日出图,如下所示,其中函数调用的层次结构被安排为以角宽度编码的弧和时间信息层。

最棒的是您可以与图表交互。例如,要放大,可以单击一个弧线,弧线及其后代将被放大为新的日出以显示更多细节。

在此处输入图像描述

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

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

然后我可以使用任何与Callgrind兼容的软件打开报告,例如qcachegrind

这取决于你想从分析中看到什么可以通过(bash)给出度量。

time python python_prog.py

即使是'/usr/bin/time'也可以通过使用'--详细'标志来输出详细的指标。

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

进入更详细的指标,如性能,时间不是唯一的指标。你可以担心内存,线程等。
分析选项:
1.line_profiler是另一个常用于逐行查找时间指标的分析器。
2.memory_profiler是一个分析内存使用情况的工具。
3.希比(来自孔雀鱼项目)配置如何使用堆中的对象。

这些是我常用的一些方法,但是如果你想了解更多,试试看这本的书这是一本关于从性能开始的非常好的书。您可以继续学习有关使用Cython和JIT(即时)编译的python的高级主题。

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

1. pip install snakeviz
2. python -m cProfile -o temp.dat <PROGRAM>.py
3. snakeviz temp.dat

在浏览器中绘制饼图。最大的部分是问题函数。非常简单。

我最近创建了金枪鱼用于可视化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

gprof2dot_magic

gprof2dot的魔术函数将任何Python语句配置为JupyterLab或Jupyter Notebook中的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')

在此处输入图片描述

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

安装:

$ pip install pyinstrument

画像及展示结果:

$ python -m pyinstrument ./prog.py

适用于python2和3。

[编辑]API的留档仅用于分析部分代码,可以在这里中找到。

如果你想创建一个累积分析器,意思是连续多次运行函数并观察结果的总和。

你可以使用这个cumulative_profiler装饰器:

它是python>=3.6特定的,但您可以删除nonlocal,因为它可以在旧版本上工作。

import cProfile, pstats
class _ProfileFunc:def __init__(self, func, sort_stats_by):self.func =  funcself.profile_runs = []self.sort_stats_by = sort_stats_by
def __call__(self, *args, **kwargs):pr = cProfile.Profile()pr.enable()  # this is the profiling sectionretval = 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 functionreturn wrapper
if callable(amount_of_times):  # incase you don't want to specify the amount of timesfunc = amount_of_times  # amount_of_times is the function in hereamount_of_times = 5  # the default amountreturn real_decorator(func)return real_decorator

示例

分析函数baz

import time
@cumulative_profilerdef 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():...

我刚刚开发了自己的分析器,灵感来自pypref_time:

https://github.com/modaresimr/auto_profiler

更新版本2

安装:

pip install auto_profiler

快速启动:

from auto_profiler import Profiler
with Profiler():your_function()

在Jupyter中使用,让您可以实时查看经过的时间

jupyter中自动分析器的实时视图

更新版本1

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

@Profiler(depth=4)

Install by: pip install auto_profiler

示例

import time # line number 1import 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 1return i*fact(i-1)
def main():for i in range(5):f1()
fact(3)

with Profiler(depth=4):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]

使用像奥斯汀这样的统计分析器,不需要检测,这意味着您可以简单地从Python应用程序中获取分析数据

austin python3 my_script.py

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

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

或者,您也可以使用Web应用程序Speedscope.app来快速可视化收集的样本。如果您安装了pprof,您还可以获取奥斯汀蟒蛇(例如pipx install austin-python)并使用austin2pprof转换为pprof格式。

但是,如果您安装了VS Code,您可以使用奥斯汀分机来获得更具交互性的体验,包括源代码热图、顶级函数和收集的调用堆栈

Austin VS Code扩展

如果你更喜欢使用终端,你也可以使用途易,它也有一个实时图形模式:

Austin TUI图形模式

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

另一个有用的包是平普勒。这是一个功能强大的分析包,能够跟踪类、对象、函数、内存泄漏等。

抓住它!

!pip install line_profiler!pip install memory_profiler!pip install pympler

装弹!

%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级别执行时间
  • sys时间:系统级执行时间
  • 合计: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'

给予:

  • 函数调用数
  • 每个函数调用都有条目(不同的)
  • 每次通话时间
  • 到该函数调用的时间(累积时间)
  • 调用etc的func/模块的名称…

累积配置文件


%memit

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

给予:

  • 内存使用

%lprun

#Example functiondef fun():for i in range(10):print(i)
#Usage: %lprun <name_of_the_function> function%lprun -f fun fun()

给予:

  • 线明智的统计

LineProfile


sys.getsizeof

sys.getsizeof('code to profile')# 64 bytes

返回对象的大小(以字节为单位)。


asizeof()来自pympler

from pympler import asizeofobj = [1,2,("hey","ha"),3]print(asizeof.asizeof(obj,stats=4))

pympler.asizeof可用于调查某些Python对象消耗了多少内存。与sys.getsizeof相反,asizeof递归地对象

pympler.asizeof


皮姆普勒的追踪器

from pympler import trackertr = tracker.SummaryTracker()def fun():li = [1,2,3]di = {"ha":"haha","duh":"Umm"}fun()tr.print_diff()

跟踪函数的生命周期。

跟踪器输出

Pympler包包含大量用于配置文件代码的高实用性函数。这里无法涵盖所有这些。有关详细配置文件实现,请参阅附加的留档。

皮姆普勒doc

最近我为PyCharm创建了一个插件,您可以在PyCharm编辑器中轻松分析和可视化line_profiler的结果。

line_profiler也在其他答案中提到过,它是一个很好的工具,可以准确地分析python解释器在某些行中花费了多少时间。

我创建的PyCharm插件可以在这里找到:https://plugins.jetbrains.com/plugin/16536-line-profiler

它需要一个名为line-profiler-pycharm的python环境中的帮助包,可以使用pip或插件本身安装。

在PyCharm中安装插件后:

  1. 使用line_profiler_pycharm.profile装饰器装饰要配置的任何函数
  2. 使用'Profile Lines'运行

结果截图:线形分析器的Py的结果

我发现cProfiler和其他资源更多地用于优化目的,而不是调试。

我制作了自己的测试模块来代替简单的python脚本速度测试。(在我的情况下1K+行py文件使用ScriptProfilerPy进行了测试,并在几分钟内将代码加速了10倍。

模块ScriptProfilerPy()将运行添加时间戳的代码。我把模块放在这里:https://github.com/Lucas-BLP/ScriptProfilerPy

用途:

from speed_testpy import ScriptProfilerPy
ScriptProfilerPy("path_to_your_script_to_test.py").Profiler()

输出:测试后的代码输出

如果您不想要命令行选项,我发现此功能快速且易于使用。

要使用,只需在要分析的每个函数上方添加@配置文件。

def profile(fnc):"""Profiles any function in following class just by adding @profile above function"""import cProfile, pstats, iodef inner (*args, **kwargs):pr = cProfile.Profile()pr.enable()retval = fnc (*args, **kwargs)pr.disable()s = io.StringIO()sortby = 'cumulative'   #Orderedps = pstats.Stats(pr,stream=s).strip_dirs().sort_stats(sortby)n=10                    #reduced the list to be monitoredps.print_stats(n)#ps.dump_stats("profile.prof")print(s.getvalue())return retvalreturn inner

每个函数的输出看起来像这样

   Ordered by: cumulative timeList reduced from 38 to 10 due to restriction <10>
ncalls  tottime  percall  cumtime  percall filename:lineno(function)1    0.000    0.000    0.002    0.002 3151212474.py:37(get_pdf_page_count)1    0.000    0.000    0.002    0.002 fitz.py:3604(__init__)1    0.001    0.001    0.001    0.001 {built-in method fitz._fitz.new_Document}1    0.000    0.000    0.000    0.000 fitz.py:5207(__del__)1    0.000    0.000    0.000    0.000 {built-in method fitz._fitz.delete_Document}1    0.000    0.000    0.000    0.000 fitz.py:4816(init_doc)1    0.000    0.000    0.000    0.000 fitz.py:5197(_reset_page_refs)1    0.000    0.000    0.000    0.000 fitz.py:4821(<listcomp>)11    0.000    0.000    0.000    0.000 fitz.py:4054(_getMetadata)1    0.000    0.000    0.000    0.000 weakref.py:241(values)

Scalene是一个新的python分析器,涵盖了许多用例,对性能的影响最小:

https://github.com/plasma-umass/scalene

它可以在非常细的级别上分析CPU、GPU和内存利用率。它还特别支持多线程/并行化python代码。