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

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

某种飞行中的堆叠痕迹?

相关问题:

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


当前回答

在Python 3中,当你第一次在调试器中使用c(ont(inue))时,pdb会自动安装一个信号处理程序。然后按Control-C会让你回到那里。在Python 2中,这里有一个单行程序,即使在相对较旧的版本中也可以工作(在2.7中测试过,但我检查了Python源代码回到2.4,看起来还可以):

import pdb, signal
signal.signal(signal.SIGINT, lambda sig, frame: pdb.Pdb().set_trace(frame))

如果你花时间调试Python, pdb是值得学习的。这个界面有点迟钝,但是对于使用过类似工具(比如gdb)的人来说应该很熟悉。

其他回答

在Solaris上,你可以使用pstack(1)。不需要修改python代码。如。

# pstack 16000 | grep : | head
16000: /usr/bin/python2.6 /usr/lib/pkg.depotd --cfg svc:/application/pkg/serv
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:282 (_wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:295 (wait) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/process/wspbus.py:242 (block) ]
[ /usr/lib/python2.6/vendor-packages/cherrypy/_init_.py:249 (quickstart) ]
[ /usr/lib/pkg.depotd:890 (<module>) ]
[ /usr/lib/python2.6/threading.py:256 (wait) ]
[ /usr/lib/python2.6/Queue.py:177 (get) ]
[ /usr/lib/python2.6/vendor-packages/pkg/server/depot.py:2142 (run) ]
[ /usr/lib/python2.6/threading.py:477 (run)
etc.

我把一些工具连接到一个正在运行的Python进程中,并注入一些代码来获得一个Python shell。

请看这里:https://github.com/albertz/pydbattach

从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>

用优秀的间谍技术就能做到。它是Python程序的抽样分析器,因此它的工作是附加到Python进程并对其调用堆栈进行抽样。因此,py-spy dump——pid $SOME_PID是转储$SOME_PID进程中所有线程调用堆栈所需要做的全部工作。通常它需要升级的特权(读取目标进程的内存)。

下面是一个线程Python应用程序的示例。

$ sudo py-spy dump --pid 31080
Process 31080: python3.7 -m chronologer -e production serve -u www-data -m
Python v3.7.1 (/usr/local/bin/python3.7)

Thread 0x7FEF5E410400 (active): "MainThread"
    _wait (cherrypy/process/wspbus.py:370)
    wait (cherrypy/process/wspbus.py:384)
    block (cherrypy/process/wspbus.py:321)
    start (cherrypy/daemon.py:72)
    serve (chronologer/cli.py:27)
    main (chronologer/cli.py:84)
    <module> (chronologer/__main__.py:5)
    _run_code (runpy.py:85)
    _run_module_as_main (runpy.py:193)
Thread 0x7FEF55636700 (active): "_TimeoutMonitor"
    run (cherrypy/process/plugins.py:518)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
Thread 0x7FEF54B35700 (active): "HTTPServer Thread-2"
    accept (socket.py:212)
    tick (cherrypy/wsgiserver/__init__.py:2075)
    start (cherrypy/wsgiserver/__init__.py:2021)
    _start_http_thread (cherrypy/process/servers.py:217)
    run (threading.py:865)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)
...
Thread 0x7FEF2BFFF700 (idle): "CP Server Thread-10"
    wait (threading.py:296)
    get (queue.py:170)
    run (cherrypy/wsgiserver/__init__.py:1586)
    _bootstrap_inner (threading.py:917)
    _bootstrap (threading.py:885)  

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