简体   繁体   English

python中的行分析类实例化

[英]Line profiling class instantiation in python

I have some existing code that I'm trying to profile. 我正在尝试分析一些现有代码。 I can successfully line profile class methods by adding a @profile decorator using kernprof . 我可以通过使用kernprof添加@profile装饰器来成功配置文件类方法。

Is there a general way to profile class instantiation? 有一种通用的方法来分析类实例化吗? I have a few classes that have a quite complex inheritance structure. 我有一些类具有相当复杂的继承结构。 When I try to profile their init functions I get something like this: 当我尝试剖析其init函数时,我得到如下信息:

Line #      Hits         Time  Per Hit   % Time  Line Contents
==============================================================
   179                                               def __init__(self, data):
   180         1    8910739.0 8910739.0    100.0          super().__init__(data)
   181         1         10.0      10.0      0.0          self.mortgage_rate = 5.2  # rate in percentage

Which is a bit useless, because I don't know what actual parent __init__ function (this class has 2 parents, each of which have one or more parents) is being called. 这有点用处,因为我不知道正在调用实际的父__init__函数(此类有2个父,每个父有一个或多个父)。

Is there any way to do this better? 有什么办法可以更好地做到这一点? For example, is there a way to automatically dive into each line, and profile the lines that get called by it (with limited depth)? 例如,是否有一种方法可以自动潜入每条线路,并分析被其调用的线路(深度有限)?

There are many ways: 有很多方法:

The trace module trace模块

The trace module in the standard python libraries provides a handy function to track the execution of your program, line by line. 标准python库中的trace模块提供了一个方便的功能,可以逐行跟踪程序的执行情况。 Therefore it's pretty easy to figure out which function is called by your __init__ method. 因此,很容易找出__init__方法调用了哪个函数。

Try to run the following codes in a python shell 尝试在python shell中运行以下代码

from MyMod import MyClass
# Do necessary preparation for your module HERE

# --- Setup and start tracing ---
import sys, trace
tracer = trace.Trace( trace=0, count=0, timing=True,  countcallers=True)
tracer.run('MyClass()') # init your class and track the function calls
tracer.results().write_results(show_missing=False) # print result to the screen

The tracer will display the calling relationships exposed by running the program. 跟踪器将显示通过运行程序公开的调用关系。

MyDependency.Fourth.__init__ -> MyDependency.Second.__init__
MyDependency.Second.__init__ -> MyDependency.Third.__init__
MyDependency.Third.__init__ -> MyDependency.First.__init__
MyClass.Child.__init__ -> MyDependency.Fourth.__init__

The trace module has also a CLI. trace模块还具有CLI。 The above python codes are equivalent to this shell command: 上面的python代码等效于此shell命令:

python -m trace -T test.py | grep __init__

where option -T is equivalent to countcallers=True . 其中选项-T等效于countcallers=True The target script test.py should contain minimal codes to initialize your class. 目标脚本test.py应该包含最少的代码来初始化您的类。

Add line-profiler to the invoked functions 将line-profiler添加到调用的函数

Now you know the names of modules, classes and methods which were invoked in your class initialization. 现在您知道在类初始化中调用的模块,类和方法的名称。 Then you can add @profile decorator to those functions. 然后,您可以将@profile装饰器添加到这些函数中。 As a side note: It's not necessary to modify the source code of each module for adding the decorator. 附带说明:无需修改每个模块的源代码即可添加装饰器。 Simply import them in your main module and run profile.add_function(MyDependency.Third.__init__) will have the same effect. 只需将它们导入您的主模块并运行profile.add_function(MyDependency.Third.__init__)将具有相同的效果。

If you want to get a chronological trace of all lines of python codes that were invoked, use the following options 如果要按时间顺序跟踪已调用的所有python代码行,请使用以下选项

tracer = trace.Trace( ignoredirs=[sys.prefix, sys.exec_prefix ], trace=1, count=0, timing=True )

It will print out 它将打印出来

 --- modulename: MyMod, funcname: __init__
0.00 MyMod.py(6):         super().__init__()
 --- modulename: MyDependency, funcname: __init__
0.00 MyDependency.py(17):         super().__init__()
...

where the first column is the walk clock time. 第一列是步行时钟时间。

The sys.setprofile method sys.setprofile方法

You can register a callback function via the sys.setprofile method. 您可以通过sys.setprofile方法注册回调函数。 It will receive events of stack transition (when a function gets called or returns). 它将接收堆栈转换事件(当函数被调用或返回时)。 Each event comes with a stack frame object, from which you can record the module, class and the function that is invoked. 每个事件都带有一个堆栈框架对象,您可以从中记录调用的模块,类和函数。

This method will give you maximum flexibility. 此方法将为您提供最大的灵活性。 For example, you can filter out function calls with stack-depth or the length of execution time. 例如,您可以筛选出具有堆栈深度或执行时间长度的函数调用。 For an usage example, please see my older post for a similar question. 有关用法示例,请参见我的旧帖子中的类似问题。

File structure for the above examples 以上示例的文件结构

The above results are based on the following module/class structure taken from another post . 以上结果基于从另一篇文章中摘录的以下模块/类结构。

File "MyDependency.py" 文件“ MyDependency.py”

class First:
    ...
class Second(First):
    ...
class Third(First):
    ...
class Fourth(Second, Third):
    ...

File "MyModel.py" 文件“ MyModel.py”

from MyDependency import Fourth
class MyClass(Fourth):
    def __init__(self):
        super().__init__()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM