Python 中的分析:谁调用了该函数?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/843671/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 20:58:19  来源:igfitidea点击:

Profiling in Python: Who called the function?

pythonprofiling

提问by Ram Rachum

I'm profiling in Python using cProfile. I found a function that takes a lot of CPU time. How do I find out which function is calling this heavy function the most?

我在 Python 中使用cProfile. 我发现了一个需要大量 CPU 时间的函数。我如何找出哪个函数最常调用这个重函数?

EDIT:

编辑:

I'll settle for a workaround: Can I write a Python line inside that heavy function that will print the name of the function that called it?

我会解决一个解决方法:我可以在那个沉重的函数中写一个 Python 行来打印调用它的函数的名称吗?

采纳答案by Nadia Alramli

That may not answer your question directly, but will definitely help. If use the profiler with option --sort cumulative it will sort the functions by cumulative time. Which is helpful to detect not only heavy functions but the functions that call them.

这可能无法直接回答您的问题,但肯定会有所帮助。如果使用带有选项 --sort 累积的探查器,它将按累积时间对函数进行排序。这不仅有助于检测重函数,还有助于检测调用它们的函数。

python -m cProfile --sort cumulative myScript.py

There is a workaround to get the caller function:

有一个解决方法来获取调用者函数:

import inspect
print inspect.getframeinfo(inspect.currentframe().f_back)[2]

You can add as many f_back as you want in case you want the caller caller etc If you want to calculate frequent calls you can do this:

您可以添加任意数量的 f_back 以防万一您想要来电者等 如果您想计算频繁的来电,您可以这样做:

record = {}

caller = inspect.getframeinfo(inspect.currentframe().f_back)[2]
record[caller] = record.get(caller, 0) + 1

Then print them by order of frequency:

然后按频率顺序打印它们:

print sorted(record.items(), key=lambda a: a[1])

回答by dbr

I almost always view the output of the cProfile module using Gprof2dot, basically it converts the output into a graphvis graph (a .dotfile), for example:

我几乎总是使用Gprof2dot查看 cProfile 模块的输出,基本上它将输出转换为 graphvis 图形(.dot文件),例如:

example gprof2dot output

示例 gprof2dot 输出

It makes it very easy to determine which function is slowest, and which function[s] called it.

它可以很容易地确定哪个函数最慢,哪个函数调用了它。

Usage is:

用法是:

python -m cProfile -o output.pstats path/to/your/script arg1 arg2
gprof2dot.py -f pstats output.pstats | dot -Tpng -o output.png

回答by Ignacio Vazquez-Abrams

inspect.stack()will give you the current caller stack.

inspect.stack()会给你当前的调用者堆栈。

回答by Anonymous

You might want to take a look at pycallgraph.

您可能想看看pycallgraph

回答by industryworker3595112

It is possible to do it using profiler cProfilein standard library.
In pstats.Stats(the profiler result) there is method print_callees(or alternatively print_callers).

可以使用cProfile标准库中的分析器来做到这一点。
pstats.Stats(探查器结果)中有方法print_callees(或替代方法print_callers)。


Example code:


示例代码:

import cProfile, pstats
pr = cProfile.Profile()
pr.enable()

# ... do something ...

pr.disable()
ps = pstats.Stats(pr).strip_dirs().sort_stats('cumulative')
ps.print_callees()

Result will be something like:

结果将类似于:

Function                           called...
                                       ncalls  tottime  cumtime
ElementTree.py:1517(_start_list)   ->   24093    0.048    0.124  ElementTree.py:1399(start)
                                        46429    0.015    0.041  ElementTree.py:1490(_fixtext)
                                        70522    0.015    0.015  ElementTree.py:1497(_fixname)
ElementTree.py:1527(_data)         ->   47827    0.017    0.026  ElementTree.py:1388(data)
                                        47827    0.018    0.053  ElementTree.py:1490(_fixtext)

On the left you have the caller, on the right you have the callee.
(for example _fixtextwas called from _data47827 times and from _start_list46429 times)

左边是调用者,右边是被调用者。
(例如_fixtext_data47827 次和从_start_list46429 次被调用)


See also:


也可以看看:


Couple of notes:


几个注意事项:

  • Your code needs to be edited for this (insert those profile statements).
    (i.e. not possible to use from command line like python -m cProfile myscript.py. Though it is possible to write separate script for that)
  • A bit unrelated, but strip_dirs()must go before sort_stats()(otherwise sorting does not work)
  • 您需要为此编辑代码(插入那些配置文件语句)。
    (即不能像 命令行 那样使用python -m cProfile myscript.py。虽然可以为此编写单独的脚本)
  • 有点无关,但strip_dirs()必须先去sort_stats()(否则排序不起作用)

回答by lothar

I have not used cProfile myself, but most profilers give you a call hierarchy.
Googling I found this slidesabout cProfile. Maybe that helps. Page 6 looks like cProfile does provide a hierarchy.

我自己没有使用过 cProfile,但大多数分析器会给你一个调用层次结构。
谷歌搜索我找到了这张关于 cProfile 的幻灯片。也许这有帮助。第 6 页看起来 cProfile 确实提供了层次结构。

回答by Mike Dunlavey

Sorry I'm not familiar with Python, but there's a general methodthat works, assuming you can manually interrupt execution at a random time.

抱歉,我不熟悉 Python,但是假设您可以在随机时间手动中断执行,则有一种通用的方法可以工作。

Just do so, and display the call stack. It will tell you, with high probability, what you want to know. If you want to be more certain, just do it several times.

这样做,并显示调用堆栈。它很可能会告诉你你想知道什么。如果你想更确定,就多做几次。

It works because the guilty caller has to be on the call stack for the fraction of time that's being wasted, which exposes it to your interrupts for that much of the time, whether it is spread over many short calls or a few lengthy ones.

之所以有效,是因为有罪的调用者必须在被浪费的那一小部分时间中处于调用堆栈上,这会在大部分时间里将其暴露给您的中断,无论它是分散在许多短调用还是一些冗长的调用上。

NOTE: This process is more like diagnosis than measurement. Suppose that bad call is wasting 90% of the time. Then each time you halt it, the probability is 90% that the bad call statement is right there on the call stack for you to see, and you will be able to see that it's bad. However, if you want to exactly measure the wastage, that's a different problem. For that, you will need a lot more samples, to see what % of them contain that call. Or alternatively, just fix the guilty call, clock the speedup, and that will tell you exactly what the wastage was.

注意:这个过程更像是诊断而不是测量。假设糟糕的通话浪费了 90% 的时间。然后每次停止它时,错误调用语句就在调用堆栈中供您查看的概率是 90%,并且您将能够看到它是错误的。但是,如果您想准确测量浪费,那就是另一个问题了。为此,您将需要更多样本,以查看其中包含该调用的百分比。或者,只需修复有罪调用,对加速进行计时,这将告诉您确切的浪费是什么。

回答by Yike Lu

Pycscope does this. I just found it today, so I can't speak to how good it is, but the few examples I've tried have been pretty good (though not perfect).

Pycscope 就是这样做的。我今天才发现它,所以我不能说它有多好,但是我尝试过的几个例子都非常好(虽然不完美)。

https://pypi.python.org/pypi/pycscope/

https://pypi.python.org/pypi/pycscope/

You would use this to generate a cscope file and then a cscope plugin from an editor, VIM specifically. I tried using it with vanilla cscope, it seems that plain cscope gets confused.

您将使用它从编辑器(特别是 VIM)生成一个 cscope 文件,然后生成一个 cscope 插件。我尝试将它与 vanilla cscope 一起使用,似乎普通的 cscope 会感到困惑。