我需要随机运行一个 python 脚本,暂停它,获取堆栈回溯,然后取消暂停它。我已经用谷歌搜索了一种方法来做到这一点,但我没有看到明显的解决方案。
8 回答
pip install statprof
(或easy_install statprof
),然后使用:
import statprof
statprof.start()
try:
my_questionable_function()
finally:
statprof.stop()
statprof.display()
此博客文章中的模块有一些背景知识:
不过,这有什么关系呢?Python 已经有两个内置的分析器: lsprof 和长期弃用的热点。lsprof 的问题在于它只跟踪函数调用。如果您在函数中有几个热循环,则 lsprof 几乎无法确定哪些是真正重要的。
几天前,我发现自己正处于 lsprof 失败的情况:它告诉我我有一个热函数,但这个函数对我来说是陌生的,而且时间足够长以至于问题出在哪里并不明显.
在 Twitter 和 Google+ 上进行了一番恳求之后,有人将我指向了 statprof。但是有一个问题:虽然它在进行统计采样(耶!),但它在采样时只跟踪函数的第一行(wtf!?)。所以我解决了这个问题,增加了文档,现在它既可用又不会误导。这是它的输出示例,更准确地定位了该热函数中的违规行:
% cumulative self time seconds seconds name 68.75 0.14 0.14 scmutil.py:546:revrange 6.25 0.01 0.01 cmdutil.py:1006:walkchangerevs 6.25 0.01 0.01 revlog.py:241:__init__ [...blah blah blah...] 0.00 0.01 0.00 util.py:237:__get__ --- Sample count: 16 Total time: 0.200000 seconds
我已经将 statprof 上传到 Python 包索引,所以安装起来几乎是微不足道的:“easy_install statprof”,你就可以开始运行了。
由于代码在 github 上,欢迎提供错误报告和改进。享受!
我可以想到几种方法来做到这一点:
而不是在程序运行时尝试获取堆栈跟踪,只需对其触发中断并解析输出即可。您可以使用 shell 脚本或另一个将您的应用程序作为子进程调用的 python 脚本来执行此操作。在这个对 C++-specific question 的回答中解释了基本思想并进行了相当彻底的辩护。
sys.excepthook
实际上,您可以注册一个记录堆栈跟踪的事后例程(使用 ),而不必解析输出。不幸的是,Python 没有任何方法可以从发生异常的点继续,因此您无法在记录后继续执行。
为了真正从正在运行的程序中获取堆栈跟踪,您
可能必须破解实现。因此,如果您真的想这样做,可能值得您花时间查看pypy,这是一个主要用 Python 编写的 Python 实现。我不知道在 pypy 中执行此操作会有多方便。我猜它不会特别方便,因为它会涉及在基本上每条指令中引入一个钩子,我认为这是非常低效的。另外,我认为与第一个选项相比不会有太多优势,除非需要很长时间才能达到您想要开始进行堆栈跟踪的状态。存在一组用于调试器的宏
gdb
,旨在帮助调试 Python 本身。gdb 可以附加到一个外部进程(在本例中是正在执行您的应用程序的 python 实例),并且可以用它做几乎任何事情。似乎该宏pystack
会在当前执行点为您提供 Python 堆栈的回溯。我认为自动化这个过程会很容易,因为你可以(在最坏的情况下)只是将文本输入到gdb
usingexpect
或其他任何东西中。
Python 已经包含了执行您所描述的操作所需的一切,无需破解解释器。
您只需将该traceback
模块与该sys._current_frames()
功能结合使用。您所需要的只是一种以所需频率转储所需回溯的方法,例如使用 UNIX 信号或其他线程。
要启动您的代码,您可以完全按照本次提交中所做的操作:
从该提交中复制
threads.py
模块,或者至少复制堆栈跟踪转储功能(ZPL 许可证,非常自由):将其连接到信号处理程序,例如,
SIGUSR1
然后,您只需要运行您的代码并根据需要使用 SIGUSR1 频繁地“杀死”它。
对于使用相同技术不时“采样”单个线程的单个函数的情况,使用另一个线程进行计时,我建议剖析Products.LongRequestLogger的代码及其测试(由您真正开发,而在Nexedi的雇员):
无论这是否是正确的“统计”分析,由 intuited 引用的Mike Dunlavey的回答提出了一个令人信服的论点,即这是一种非常强大的“性能调试”技术,我有个人经验,它确实有助于快速放大真实性能问题的原因。
要为 Python 实现外部统计分析器,您将需要一些通用调试工具来询问另一个进程,以及一些 Python 特定工具来获取解释器状态。
这通常不是一个简单的问题,但您可能想尝试从 GDB 7 和相关的 CPython 分析工具开始。
在提出这个问题七年后,现在有几个很好的 Python 统计分析器可用。除了Dmitry Trofimov在这个答案中已经提到的 vmprof 之外,还有vprof和pyflame。它们都以一种或另一种方式支持火焰图,让您很好地了解时间花在哪里。
Austin是一个用于 CPython 的帧堆栈采样器,可用于为 Python 制作统计分析器,无需检测并引入最小开销。最简单的做法是使用 FlameGraph 管道输出 Austin 的输出。但是,您可以使用自定义应用程序获取 Austin 的输出,以制作您自己的探查器,该分析器正好针对您的需求。
这是 Austin TUI 的屏幕截图,它是一个终端应用程序,它提供了一个正在运行的 Python 应用程序中发生的所有事情的顶部视图。
这是 Web Austin,一个 Web 应用程序,它向您显示收集的样本的实时火焰图。您可以配置为应用程序提供服务的地址,然后允许您进行远程分析。
有一个用 C 语言编写的跨平台采样(统计)Python 分析器,称为vmprof-python。由 PyPy 团队成员开发,支持 PyPy 和 CPython。它适用于 Linux、Mac OSX 和 Windows。它是用 C 编写的,因此开销很小。它分析 Python 代码以及从 Python 代码进行的本机调用。此外,除了函数名称之外,它还有一个非常有用的选项来收集有关函数内部执行行的统计信息。它还可以分析内存使用情况(通过跟踪堆大小)。
它可以通过 API 或控制台从 Python 代码中调用。有一个 Web UI 可以查看配置文件转储:vmprof.com,它也是开源的。
此外,一些 Python IDE(例如 PyCharm)与其集成,允许运行分析器并在编辑器中查看结果。
对于 Python,有py-spy可以转储堆栈跟踪。转储可以通过speedscope进行分析
资料来源:指南