You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用GDB调试asyncio协程?解决aiohttp应用栈追踪缺失问题

Debugging Asyncio/Aiohttp Apps with GDB: Viewing Coroutine Stacks & Controlling Execution

Hey there, I've run into this exact issue before—when debugging asyncio apps with GDB, the default py-bt only shows the event loop's main stack because asyncio coroutines are managed as Task objects, each with their own separate call stacks that aren't automatically traversed by the basic command. Let's break down how to fix this and take control of your coroutines:

1. List & Inspect Active Asyncio Tasks

Most modern GDB Python extensions (built for Python asyncio debugging) include commands to list all running/suspended tasks. Try these first:

Step 1: List all tasks

Run this in GDB to get an overview of active coroutines:

(gdb) py-list-tasks

You'll get output like this:

Found 2 active tasks:
Task 0x7f8a12345670: <handle_request() running at ./my-server/main.py:65>
Task 0x7f8a12345ab0: <fetch_external_data() suspended at ./my-server/utils.py:32>

Step 2: View a specific coroutine's stack

Once you have the task address, pass it to py-bt to see its actual call stack:

(gdb) py-bt 0x7f8a12345670

This will show you the full traceback for that coroutine, including where it's stuck or suspended:

Traceback (most recent call first):
File "./my-server/utils.py", line 35, in fetch_external_data
await asyncio.sleep(5)
File "./my-server/main.py", line 68, in handle_request
data = await fetch_external_data()
File "/usr/local/lib/python3.7/dist-packages/aiohttp/web_protocol.py", line 422, in _handle_request
resp = await self._request_handler(request)

2. Manual Task Inspection (If py-list-tasks Isn't Available)

If your GDB extension doesn't have the task-listing command, you can manually dig into the asyncio event loop to find tasks:

  1. First, get the current running event loop:
(gdb) py import asyncio
(gdb) py loop = asyncio.get_running_loop()
  1. Check ready (about to run) and scheduled (waiting) tasks:
(gdb) py print("Ready tasks:", [t for t in loop._ready])
(gdb) py print("Scheduled tasks:", [t for t in loop._scheduled])
  1. For a specific task, print its stack directly:
(gdb) py task = loop._ready[0]  # Pick the first ready task
(gdb) py print("Coroutine stack:")
(gdb) py for frame in task.get_stack():
>         print(f"{frame.f_code.co_filename}:{frame.f_lineno} - {frame.f_code.co_name}")

3. Interrupting & Resuming Coroutines

Setting Breakpoints in Coroutines

Just like regular Python code, you can set breakpoints directly in coroutine code to pause execution when it hits that line:

(gdb) b ./my-server/main.py:68
(gdb) c

When the coroutine reaches line 68, GDB will pause, and you can use py-bt (with or without the task address) to inspect the stack.

Canceling/Suspending a Coroutine

If you need to force a coroutine to stop, you can cancel it directly from GDB:

(gdb) py task.cancel()

This will raise a asyncio.CancelledError in the coroutine—make sure your app handles this properly, or it might crash.

Resuming Execution

To let the event loop continue scheduling all coroutines, just use the standard GDB continue command:

(gdb) c

If you want to run a specific coroutine to completion (outside the main event loop), you can do this (note: use carefully, as it might interfere with the running app):

(gdb) py asyncio.run_until_complete(task)

Quick Tips

  • Avoid running your Python app with the -O (optimize) flag—it strips out stack frame metadata that GDB needs to show coroutine stacks.
  • Make sure you're using a GDB version compatible with your Python 3.7 installation (matching Python debug symbols helps too).
  • If you're using a custom GDB Python extension, double-check that it explicitly supports asyncio task traversal (many newer extensions do out of the box).

内容的提问来源于stack exchange,提问作者AivanF.

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 08:24:11