我有一个Python应用程序,它不时卡住,我不知道在哪里。
是否有任何方法向Python解释器发出信号,以显示正在运行的确切代码?
某种飞行中的堆叠痕迹?
相关问题:
从Python代码中的方法打印当前调用堆栈 检查正在运行的进程正在做什么:打印未检测的Python程序的堆栈跟踪
我有一个Python应用程序,它不时卡住,我不知道在哪里。
是否有任何方法向Python解释器发出信号,以显示正在运行的确切代码?
某种飞行中的堆叠痕迹?
相关问题:
从Python代码中的方法打印当前调用堆栈 检查正在运行的进程正在做什么:打印未检测的Python程序的堆栈跟踪
当前回答
安装信号处理程序的建议很好,我经常使用它。例如,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通常可以让您很好地了解进程正在做什么。
其他回答
我正在寻找一段时间的解决方案来调试我的线程,我发现它在这里感谢haridsv。我使用稍微简化的版本,使用traceback.print_stack():
import sys, traceback, signal
import threading
import os
def dumpstacks(signal, frame):
id2name = dict((th.ident, th.name) for th in threading.enumerate())
for threadId, stack in sys._current_frames().items():
print(id2name[threadId])
traceback.print_stack(f=stack)
signal.signal(signal.SIGQUIT, dumpstacks)
os.killpg(os.getpgid(0), signal.SIGQUIT)
为了满足我的需要,我还按名称筛选线程。
我几乎总是处理多线程,主线程通常不做太多,所以最有趣的是转储所有堆栈(这更像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)
我把一些工具连接到一个正在运行的Python进程中,并注入一些代码来获得一个Python shell。
请看这里:https://github.com/albertz/pydbattach
在这里真正帮助我的是spiv的技巧(如果我有声望分数,我会投票并评论),即从一个未准备好的Python进程中获得堆栈跟踪。除非我修改了gdbinit脚本,否则它无法工作。所以:
下载https://svn.python.org/projects/python/trunk/Misc/gdbinit并将其放在~/.gdbinit中 编辑它,将PyEval_EvalFrame更改为PyEval_EvalFrameEx [edit:不再需要;链接的文件在2010-01-14已经有此更改] 附加gdb: gdb -p PID 获取python堆栈跟踪:pystack
如何调试任何函数在控制台:
创建使用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)
愉快的调试:)