35

我正在尝试转储所有活动线程的列表,包括每个线程的当前堆栈。我可以使用 threading.enumerate() 获取所有线程的列表,但我无法找到从那里进入堆栈的方法。

背景:Zope/Plone 应用程序时常出现异常,消耗 100% 的 cpu,需要重新启动。我感觉这是一个没有正确终止的循环,但我无法在测试环境中重现它以进行验证。我设法注册了一个可以从外部触发的信号处理程序,因此一旦情况再次发生,我就可以触发一些代码。如果我可以转储所有活动线程的堆栈跟踪,那将给我一个线索是哪里出了问题。洞东西在python 2.4上运行......

任何关于如何追踪此类情况的想法都值得赞赏:)

干杯,克里斯

4

6 回答 6

43

正如 jitter 在较早的答案中指出的那样,sys._current_frames()为您提供了 v2.5+ 所需的内容。对于懒惰的人,以下代码片段对我有用,可能会对您有所帮助:

print >> sys.stderr, "\n*** STACKTRACE - START ***\n"
code = []
for threadId, stack in sys._current_frames().items():
    code.append("\n# ThreadID: %s" % threadId)
    for filename, lineno, name, line in traceback.extract_stack(stack):
        code.append('File: "%s", line %d, in %s' % (filename,
                                                    lineno, name))
        if line:
            code.append("  %s" % (line.strip()))

for line in code:
    print >> sys.stderr, line
print >> sys.stderr, "\n*** STACKTRACE - END ***\n"
于 2011-09-06T09:02:15.017 回答
32

对于 Python 3.3 及更高版本,有faulthandler.dump_traceback().

下面的代码产生类似的输出,但包含线程名称并且可以增强以打印更多信息。

for th in threading.enumerate():
    print(th)
    traceback.print_stack(sys._current_frames()[th.ident])
    print()
于 2014-06-20T19:46:18.353 回答
10

使用 Zope 时,您要安装Products.signalstackmr.freeze;这些就是为此目的而设计的!

向您的 Zope 服务器发送一个 USR1 信号,它会立即将所有线程的堆栈跟踪转储到控制台。即使所有 Zope 线程都被锁定,它也会这样做。

在引擎盖下,这些包间接使用threadframes;对于 Python 2.5 及更高版本,当使用 Zope 时,您可以使用该函数构建相同的sys._current_frames()功能来访问每个线程的堆栈帧。

Zope 2.12.5 开始,此功能被集成到 Zope 本身中,不再需要安装额外的包。

于 2009-06-24T14:18:14.623 回答
7

2.4. 太糟糕了。从 Python 2.5 开始,有sys._current_frames().

但是你可以试试threadframe。如果makefile给你带来麻烦,你可以试试这个setup.py for threadframe

使用 threadframe 时的示例输出

于 2009-06-23T14:31:33.357 回答
1

只是为了完整起见,Products.LongRequestLogger对识别瓶颈非常有帮助,为此它会以特定的时间间隔转储堆栈跟踪。

于 2015-11-01T20:32:30.343 回答
0

ASPN上有一个适用的配方。您可以使用threading.enumerate()来获取所有 tid,然后只需调用 _async_raise() 并使用一些合适的异常来强制堆栈跟踪。

于 2009-06-23T14:26:48.357 回答