应使用 async with asyncio.taskgroup() 替代 asyncio.gather() 或手动 create_task(),以避免任务泄漏、资源不释放和异常静默;必须在 async with 块内用 tg.create_task() 启动任务,用 except* 捕获 exceptiongroup,并显式保存 task 对象调用 .result() 获取结果。

直接结论:用 async with asyncio.TaskGroup() 替代 asyncio.gather() 或手动 create_task(),能避免任务泄漏、资源不释放、异常静默三大问题——前提是必须用对语法和异常处理方式。
TaskGroup 必须写在 async with 块里,不能提前创建或手动管理
它不是普通类,不能 tg = asyncio.TaskGroup(),也不能在 async with 外调用 create_task()。一旦漏掉 async with,运行时立刻报 RuntimeError: TaskGroup is closed 或 no active task group。
- 所有子任务必须在
async with asyncio.TaskGroup() as tg:块内,通过tg.create_task()启动 - 用
asyncio.create_task()启动的任务不会被纳入生命周期管理,等于“裸奔” - 块退出时(无论正常还是异常),框架自动等待或取消所有已启动任务,无需手写
try/finally + await task - 不能在块外
await某个子任务,否则破坏结构化边界,行为未定义
异常必须用 except* 捕获,老式 except 会完全失效
TaskGroup 抛出的是 ExceptionGroup(或 BaseExceptionGroup),不是单个异常。写 except ValueError: 根本捕不到——因为 ValueError 被包在里面了。
- 正确写法是
except* ValueError as eg:,其中eg.exceptions是匹配到的所有ValueError实例列表 - 可并列多个
except*,比如except* httpx.HTTPStatusError:和except* asyncio.TimeoutError: - 不要用
except* BaseException:兜底,它会捕获KeyboardInterrupt等信号,生产环境慎用 -
print(eg)只输出摘要,要查完整 traceback 得遍历:for exc in eg.exceptions: print(repr(exc))
TaskGroup 不返回结果,需显式保存 Task 对象再调 .result()
它不提供类似 gather() 那样的结果列表,也不把异常塞进返回值。你要自己存 Task 引用,最后统一取值。
- 每个
tg.create_task()返回一个Task对象,必须赋值给变量(如task1 = tg.create_task(...)) - 块结束后,用
task1.result()拿结果:成功则返回值,失败则再次抛出原始异常(已在ExceptionGroup中) - 顺序不保证,别依赖执行顺序;若需按序收集,建议配合
asyncio.Queue或带索引的封装 - 不要对普通
list或dict直接并发读写——TaskGroup不提供数据同步能力,仍需asyncio.Lock或asyncio.Queue
取消传播是协作式的,子任务得响应 CancelledError
当某个子任务异常,TaskGroup 会向其余任务发 CancelledError,但不会强制中断协程——它靠子任务在 async with 或 try/finally 中自行清理。
- 如果子任务没写清理逻辑(比如没用
async with httpx.AsyncClient()),CancelledError可能被忽略,连接池或文件句柄就卡住 - 轻量纯计算任务响应快,I/O 密集型任务响应慢,这“等待清理”的时间就是安全成本,不是性能缺陷
- 对比
gather(return_exceptions=True),你不用再遍历结果判断类型,异常聚合后一次抛出,处理更集中 - 高并发场景下,快速熔断 + 协作清理,反而降低尾延迟和资源争用概率
最容易被忽略的一点:你写的 except* 不只是语法变化,它是整个错误传播链的守门人。漏掉 *,异常就静默吞掉或向上冒泡,async with 的清理逻辑可能根本没执行——连接没关、锁没放、临时文件残留,后续请求就卡在这儿了。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











