7

我必须运行一个遗留的 Zope2 网站并对它有些不满。最大的问题是,有时它只是锁定,以 100% 的 CPU 负载运行,不再响应请求。虽然该问题无法定期重现,但包含 3 个动态图的页面有时会触发它,因此我怀疑某种竞争条件会导致无限循环或卡住的忙等待。

问题是,我还没有找到调试这个东西的方法。Zope 日志中没有任何内容,系统日志中也没有任何内容。我尝试了这个问题的建议来获取堆栈跟踪,但唯一有效的信号是SIGKILL.

当它卡住时,是否还有另一种可能性来找出该过程的确切位置?

4

6 回答 6

9

您可以使用pyrasite打印出漂亮的堆栈跟踪。

首先,您需要安装 gdb。

# Redhat, CentOS, etc
$ yum install gdb

# Ubuntu, Debian, etc
$ apt-get update && apt-get install gdb

然后,安装pyrasite。

$ pip install pyrasite

使用ps或其他方法查找卡住的 python 进程的进程 ID 并pyrasite-shell使用它运行。

# Assuming process ID is 12345
$ pyrasite-shell 12345

您现在应该看到一个 python REPL。在 REPL 中运行以下命令以查看所有线程的堆栈跟踪。

import sys, traceback
for thread_id, frame in sys._current_frames().items():
    print 'Stack for thread {}'.format(thread_id)
    traceback.print_stack(frame)
    print ''
于 2017-06-03T00:23:35.767 回答
2

请参阅我对这个 SO 问题的回答,使用Products.signalstack。它在产品注册时注册与您已经找到的答案相同的处理程序。也许它对你更有效。

如果没有,您可能遇到了操作系统级别的 I/O 问题,您唯一的希望是将 gdb 附加到该进程。在 Stack Overflow 上搜索 gdb 答案;这里有丰富的信息!

于 2009-11-23T15:26:46.400 回答
1

您可以尝试将调试器附加到正在运行的进程。另请参阅此问题

于 2009-11-23T09:17:42.663 回答
1

虽然 pyrasite 可能会起作用,但它不能处理一些极端情况并静默挂起/失败。

如果包没有按预期工作,可以手动执行包在引擎盖下所做的事情,以找出问题所在。

  • 将 gdb 附加到 Python 进程:(可能需要。)gdb -p <PID>sudo
  • 通过在 gdb 中键入命令来运行以下函数
set $gstate = PyGILState_Ensure()
call          PyRun_SimpleString(" <some Python code> ")
call          PyGILState_Release($gstate)

有关函数,请参阅 Python API 文档:1 2


如果 Python 没有使用调试符号编译,则有必要为函数提供显式数据类型:

参考Python源码https://github.com/python/cpython/blob/4fe5585240f64c3d14eb635ff82b163f92074b3a/Include/pystate.h#L86-L88,类型PyGILState_STATE是一个有2个值的枚举,所以我们“猜测”我们可以使用int. (虽然它可能不起作用。

总之,根据文档,功能的“正确(受上述限制)”命令是

set $gstate = ((int (*)())            PyGILState_Ensure ) ()
call          ((int (*)(const char*)) PyRun_SimpleString) (" <some Python code> ")
call          ((void(*)(int))         PyGILState_Release) ($gstate)

此解决方案不依赖于 gdb 的 Python 调试扩展。否则,可以简单地运行py-bt.


我有一个更新的 pyrasite 分支,(目前)命名为 pyrasite-ng。如果有任何错误可以在那里报告,希望我能尽快修复它。

于 2021-12-11T01:31:37.710 回答
0

如果进程卡在没有其他信号通过的方式,您可能需要考虑从调试器运行它,而不是尝试在运行时附加到它。

此外,它可能对其他调试策略很有用,例如关闭代码的某些部分以找出它仍然可重现的最小情况,以便查看导致它更好的原因。

于 2009-11-23T09:21:07.920 回答
0

在互联网上转了一圈后,我终于来到了这里: http: //podoliaka.org/2016/04/10/debugging-cpython-gdb/ - 详细描述了所有部分如何组合在一起。我的报价是'gdb /usr/bin/python -p $PID' - 需要可执行文件的名称才能让gdb找到正确的调试信息文件。

于 2016-09-26T22:21:43.360 回答