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

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

某种飞行中的堆叠痕迹?

相关问题:

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


当前回答

我几乎总是处理多线程,主线程通常不做太多,所以最有趣的是转储所有堆栈(这更像Java的转储)。下面是一个基于这个博客的实现:

import threading, sys, traceback

def dumpstacks(signal, frame):
    id2name = dict([(th.ident, th.name) for th in threading.enumerate()])
    code = []
    for threadId, stack in sys._current_frames().items():
        code.append("\n# Thread: %s(%d)" % (id2name.get(threadId,""), 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()))
    print("\n".join(code))

import signal
signal.signal(signal.SIGQUIT, dumpstacks)

其他回答

安装信号处理程序的建议很好,我经常使用它。例如,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通常可以让您很好地了解进程正在做什么。

没有办法钩入正在运行的python进程并获得合理的结果。如果进程锁定,我所做的是连接strace并试图弄清楚到底发生了什么。

不幸的是,strace通常是“修复”竞争条件的观察器,因此输出在那里也是无用的。

Python -dv yourscript.py

这将使解释器以调试模式运行,并为您提供解释器正在做什么的跟踪。

如果你想交互调试代码,你应该像这样运行它:

Python -m PDB yourscript.py

它告诉python解释器使用模块“pdb”(python调试器)运行你的脚本,如果你这样运行它,解释器将以交互模式执行,很像GDB

在运行代码时,您可以插入这个小片段,以查看格式化良好的打印堆栈跟踪。它假设在项目的根目录中有一个名为logs的文件夹。

# DEBUG: START DEBUG -->
import traceback

with open('logs/stack-trace.log', 'w') as file:
    traceback.print_stack(file=file)
# DEBUG: END DEBUG --!

如何调试任何函数在控制台:

创建使用pdb.set_trace()的函数,然后是要调试的函数。

>>> import pdb
>>> import my_function

>>> def f():
...     pdb.set_trace()
...     my_function()
... 

然后调用创建的函数:

>>> f()
> <stdin>(3)f()
(Pdb) s
--Call--
> <stdin>(1)my_function()
(Pdb) 

愉快的调试:)