如何使用 GDB 调试 asyncio 协程?

How to debug asyncio coroutines with GDB?

There is some extension 允许使用 GDB 查看 Python 进程的详细信息,我安装并尝试将其与基于 aiohttp 的挂起网络应用程序一起使用。但是,无论正在处理什么请求,我总是只看到主堆栈跟踪,没有任何有用的信息:

(gdb) py-bt
Traceback (most recent call first):
  File "/usr/lib/python3.7/selectors.py", line 468, in select
    fd_event_list = self._selector.poll(timeout, max_ev)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 1739, in _run_once
    event_list = self._selector.select(timeout)
  File "/usr/lib/python3.7/asyncio/base_events.py", line 539, in run_forever
    self._run_once()
  File "/usr/lib/python3.7/asyncio/base_events.py", line 571, in run_until_complete
    self.run_forever()
  File "/usr/local/lib/python3.7/dist-packages/aiohttp/web.py", line 433, in run_app
    reuse_port=reuse_port))
  File "./my-server/main.py", line 98, in <module>
    web.run_app(app_main, host=host, port=port)

这可能是 asyncio 为每个协程创建的单独堆栈跟踪的结果。

目标是正确调试 asyncio 应用程序。那么,如何查看执行堆栈和 interrupt/continue 协程?

经过长时间的挖掘,我找到了一个替代解决方案:简单而神奇 py-spy!与 gdb 相比,它不需要目标进程是 运行 和 Python 的特殊构建,处理异步函数也没有问题。下面是一个简单的使用场景:

pip install py-spy

# Get stack traces of active threads:
py-spy dump --pid 1

# Watch executing functions in realtime:
py-spy top --pid 1

此处提供完整说明:https://github.com/benfred/py-spy

注意,在某些环境中很重要:就像 gdb 一样,要在 Docker 容器中使用,py-spy 需要设置标志 SYS_PTRACE