转储所有活动线程的堆栈跟踪
我想要获取一个所有活跃线程的列表,并查看每个线程的当前执行情况。我可以通过使用 threading.enumerate() 来获取所有线程的列表,但我不知道怎么从这个列表中获取到每个线程的执行堆栈。
背景:我的 Zope/Plone 应用偶尔会出现问题,导致 CPU 使用率达到 100%,需要重启。我觉得可能是某个循环没有正确结束,但我在测试环境中无法重现这个问题。我设法注册了一个信号处理器,可以从外部触发,这样当问题再次出现时,我可以执行一些代码。如果我能获取到所有活跃线程的堆栈跟踪信息,那就能让我找到问题的线索。整个应用运行在 Python 2.4 上……
如果有人有办法追踪到这种情况,我会非常感激 :)
谢谢,
Chriss
6 个回答
对于Python 3.3及以后的版本,有一个功能叫做 faulthandler.dump_traceback()
。
下面的代码可以产生类似的输出,但它会显示线程的名称,并且可以改进以打印更多的信息。
for th in threading.enumerate():
print(th)
traceback.print_stack(sys._current_frames()[th.ident])
print()
正如jitter在之前的回答中提到的,sys._current_frames()
可以满足你在Python 2.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"
在使用Zope的时候,你可能需要安装Products.signalstack
或者mr.freeze,这两个工具就是为了这个目的而设计的!
你可以给你的Zope服务器发送一个USR1信号,这样它就会立刻把所有线程的堆栈信息打印到控制台上。即使所有的Zope线程都被锁住了,它也能做到这一点。
这些工具的底层实际上是间接使用了threadframes
;对于Python 2.5及以上版本,如果不使用Zope,你可以通过sys._current_frames()
这个函数来获取每个线程的堆栈信息。
从Zope 2.12.5开始,这个功能已经集成到Zope里面了,所以不需要再安装额外的工具了。