我有一个Python应用程序,它不时卡住,我不知道在哪里。

是否有任何方法向Python解释器发出信号,以显示正在运行的确切代码?

某种飞行中的堆叠痕迹?

相关问题:

从Python代码中的方法打印当前调用堆栈 检查正在运行的进程正在做什么:打印未检测的Python程序的堆栈跟踪


当前回答

我有一个用于这种情况的模块——一个进程将运行很长时间,但有时由于未知和不可复制的原因而卡住。它有点俗气,只在unix上工作(需要信号):

import code, traceback, signal

def debug(sig, frame):
    """Interrupt running process, and provide a python prompt for
    interactive debugging."""
    d={'_frame':frame}         # Allow access to frame object.
    d.update(frame.f_globals)  # Unless shadowed by global
    d.update(frame.f_locals)

    i = code.InteractiveConsole(d)
    message  = "Signal received : entering python shell.\nTraceback:\n"
    message += ''.join(traceback.format_stack(frame))
    i.interact(message)

def listen():
    signal.signal(signal.SIGUSR1, debug)  # Register handler

要使用,只需在程序启动时调用listen()函数(您甚至可以将其插入site.py以让所有python程序使用它),并让它运行。在任何时候,使用kill或python向进程发送一个SIGUSR1信号:

    os.kill(pid, signal.SIGUSR1)

这将导致程序在当前位置中断到python控制台,向您显示堆栈跟踪,并允许您操作变量。使用control-d (EOF)继续运行(不过请注意,您可能会在您发出信号时中断任何I/O等,因此它不是完全非侵入式的。

我有另一个脚本,做同样的事情,除了它通过管道与正在运行的进程通信(允许调试后台进程等)。在这里发布有点大,但我已经把它作为python食谱添加了。

其他回答

traceback模块有一些不错的函数,其中包括:

import traceback

traceback.print_stack()

从Austin 3.3开始,您可以使用-w/——where选项来发出当前堆栈跟踪。参见https://stackoverflow.com/a/70905181/1838793

如果您想查看正在运行的Python应用程序,以类似top的方式查看“活动”调用堆栈,可以使用austin-tui (https://github.com/p403n1x87/austin-tui)。你可以从PyPI安装它。

pipx install austin-tui

请注意,它需要austin二进制文件才能工作(https://github.com/p403n1x87/austin),但随后您可以使用

austin-tui -p <pid>

Pydb值得一看,它是“松散地基于gdb命令集的Python调试器的扩展版本”。它包括信号管理器,可以在发送指定信号时启动调试器。

2006年的“代码之夏”项目研究了在名为mpdb的模块中向pydb添加远程调试功能。

如果您使用的是Linux系统,请使用出色的gdb和Python调试扩展(可以在Python -dbg或Python -debuginfo包中)。它还有助于多线程应用程序、GUI应用程序和C模块。

使用以下命令运行程序:

$ gdb -ex r --args python <programname>.py [arguments]

这指示gdb准备python <programname>.py <arguments>并运行它。

现在当你的程序挂起时,切换到gdb控制台,按Ctr+C并执行:

(gdb) thread apply all py-list

参见示例会话和更多信息在这里和这里。

安装信号处理程序的建议很好,我经常使用它。例如,bzr默认安装一个SIGQUIT处理程序,调用pdb.set_trace()立即将您放入pdb提示符中。(参见bzrlib。进入模块的源代码以获取确切的细节。)使用pdb,您不仅可以获得当前堆栈跟踪(使用(w)here命令),还可以检查变量等。

然而,有时我需要调试一个我没有预见到在其中安装信号处理程序的进程。在linux上,您可以将gdb附加到进程,并使用一些gdb宏获得python堆栈跟踪。将http://svn.python.org/projects/python/trunk/Misc/gdbinit放在~/中。gdbinit,然后:

附加gdb: gdb -p PID 获取python堆栈跟踪:pystack

不幸的是,它不是完全可靠的,但它在大多数时候都是有效的。参见https://wiki.python.org/moin/DebuggingWithGdb

最后,附加strace通常可以让您很好地了解进程正在做什么。