【问题标题】:Dump stacktraces of all active Threads转储所有活动线程的堆栈跟踪
【发布时间】:2009-06-23 14:13:38
【问题描述】:

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

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

感谢任何关于如何追踪此类情况的想法:)

干杯, 克里斯

【问题讨论】:

    标签: python multithreading plone zope


    【解决方案1】:

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

    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"
    

    【讨论】:

      【解决方案2】:

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

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

      for th in threading.enumerate():
          print(th)
          traceback.print_stack(sys._current_frames()[th.ident])
          print()
      

      【讨论】:

      • 当心:faulthandler 代码在 python 3.9.4 中存在段错误(目前是 ubuntu 21.04 中的最新版本),大约两个月前在 3.9.7 python 版本中已修复此问题
      【解决方案3】:

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

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

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

      截至Zope 2.12.5,此功能已集成到 Zope 本身中,不再需要安装其他软件包。

      【讨论】:

      • 现在在 Plone 中“不需要特殊包”stackoverflow.com/a/36633215/3046069
      • @Danimal:谢谢,已添加到帖子中。 2.12.5 在我写完这个答案一年后发布。
      • threadframes 的链接现在已经失效,但无论如何,从 python 2.5 开始,您可以使用sys._current_frames()
      • @ImranRashid:是的,我的回答已经表明你可以。我已经替换了损坏的链接。
      【解决方案4】:

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

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

      Sample output when using threadframe

      【讨论】:

        【解决方案5】:

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

        【讨论】:

          【解决方案6】:

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

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2013-10-06
            • 2022-01-02
            • 1970-01-01
            • 1970-01-01
            • 2012-08-24
            • 1970-01-01
            • 1970-01-01
            • 2015-08-22
            相关资源
            最近更新 更多