18

我需要随机运行一个 python 脚本,暂停它,获取堆栈回溯,然后取消暂停它。我已经用谷歌搜索了一种方法来做到这一点,但我没有看到明显的解决方案。

4

8 回答 8

13

statprof模块

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 上,欢迎提供错误报告和改进。享受!

于 2012-04-26T12:38:48.157 回答
5

我可以想到几种方法来做到这一点:

  • 而不是在程序运行时尝试获取堆栈跟踪,只需对其触发中断并解析输出即可。您可以使用 shell 脚本或另一个将您的应用程序作为子进程调用的 python 脚本来执行此操作。在这个对 C++-specific question 的回答中解释了基本思想并进行了相当彻底的辩护。

    • sys.excepthook实际上,您可以注册一个记录堆栈跟踪的事后例程(使用 ),而不必解析输出。不幸的是,Python 没有任何方法可以从发生异常的点继续,因此您无法在记录后继续执行。
  • 为了真正从正在运行的程序中获取堆栈跟踪,您可能必须破解实现。因此,如果您真的想这样做,可能值得您花时间查看pypy,这是一个主要用 Python 编写的 Python 实现。我不知道在 pypy 中执行此操作会有多方便。我猜它不会特别方便,因为它会涉及在基本上每条指令中引入一个钩子,我认为这是非常低效的。另外,我认为与第一个选项相比不会有太多优势,除非需要很长时间才能达到您想要开始进行堆栈跟踪的状态。

  • 存在一组用于调试器的宏gdb,旨在帮助调试 Python 本身。gdb 可以附加到一个外部进程(在本例中是正在执行您的应用程序的 python 实例),并且可以用它做几乎任何事情。似乎该宏pystack会在当前执行点为您提供 Python 堆栈的回溯。我认为自动化这个过程会很容易,因为你可以(在最坏的情况下)只是将文本输入到gdbusingexpect或其他任何东西中。

于 2011-04-11T04:14:55.420 回答
3

Python 已经包含了执行您所描述的操作所需的一切,无需破解解释器。

您只需将该traceback模块与该sys._current_frames()功能结合使用。您所需要的只是一种以所需频率转储所需回溯的方法,例如使用 UNIX 信号或其他线程。

要启动您的代码,您可以完全按照本次提交中所做的操作:

  1. 从该提交中复制threads.py模块,或者至少复制堆栈跟踪转储功能(ZPL 许可证,非常自由):

  2. 将其连接到信号处理程序,例如,SIGUSR1

然后,您只需要运行您的代码并根据需要使用 SIGUSR1 频繁地“杀死”它。

对于使用相同技术不时“采样”单个线程的单个函数的情况,使用另一个线程进行计时,我建议剖析Products.LongRequestLogger的代码及其测试(由您真正开发,而在Nexedi的雇员):

无论这是否是正确的“统计”分析,由 intuited 引用的Mike Dunlavey回答提出了一个令人信服的论点,即这是一种非常强大的“性能调试”技术,我有个人经验,它确实有助于快速放大真实性能问题的原因。

于 2012-03-16T12:33:13.317 回答
2

要为 Python 实现外部统计分析器,您将需要一些通用调试工具来询问另一个进程,以及一些 Python 特定工具来获取解释器状态。

这通常不是一个简单的问题,但您可能想尝试从 GDB 7 和相关的 CPython 分析工具开始。

于 2011-04-11T04:39:09.640 回答
2

在提出这个问题七年后,现在有几个很好的 Python 统计分析器可用。除了Dmitry Trofimov这个答案中已经提到的 vmprof 之外,还有vprofpyflame。它们都以一种或另一种方式支持火焰图,让您很好地了解时间花在哪里。

于 2018-08-23T12:13:40.477 回答
2

Austin是一个用于 CPython 的帧堆栈采样器,可用于为 Python 制作统计分析器,无需检测并引入最小开销。最简单的做法是使用 FlameGraph 管道输出 Austin 的输出。但是,您可以使用自定义应用程序获取 Austin 的输出,以制作您自己的探查器,该分析器正好针对您的需求。

这是 Austin TUI 的屏幕截图,它是一个终端应用程序,它提供了一个正在运行的 Python 应用程序中发生的所有事情的顶部视图。 奥斯汀途易

这是 Web Austin,一个 Web 应用程序,它向您显示收集的样本的实时火焰图。您可以配置为应用程序提供服务的地址,然后允许您进行远程分析。

在此处输入图像描述

于 2019-05-05T15:07:03.490 回答
1

有一个用 C 语言编写的跨平台采样(统计)Python 分析器,称为vmprof-python。由 PyPy 团队成员开发,支持 PyPy 和 CPython。它适用于 Linux、Mac OSX 和 Windows。它是用 C 编写的,因此开销很小。它分析 Python 代码以及从 Python 代码进行的本机调用。此外,除了函数名称之外,它还有一个非常有用的选项来收集有关函数内部执行行的统计信息。它还可以分析内存使用情况(通过跟踪堆大小)。

它可以通过 API 或控制台从 Python 代码中调用。有一个 Web UI 可以查看配置文件转储:vmprof.com,它也是开源的

此外,一些 Python IDE(例如 PyCharm)与其集成,允许运行分析器并在编辑器中查看结果。

于 2017-03-24T17:01:07.830 回答
1

对于 Python,有py-spy可以转储堆栈跟踪。转储可以通过speedscope进行分析

资料来源:指南

于 2020-05-13T14:17:19.680 回答