taskgroup 是 python 3.11+ 的结构化并发上下文管理器,强制子任务生命周期绑定并支持短路失败;而 create_task 仅调度协程,无自动等待或异常传播机制。

TaskGroup 是什么,它和 asyncio.create_task 有什么本质区别?
TaskGroup 不是任务的容器,而是一个结构化并发的上下文管理器——它强制所有子任务在退出时完成或被取消,避免“幽灵任务”泄漏。这和手动调用 asyncio.create_task 有根本差异:后者只是把协程调度进事件循环,不提供生命周期绑定;而 TaskGroup 的 <strong>exit</strong> 会等待所有子任务结束,并在任一任务抛出未处理异常时立即取消其余任务(类似“短路失败”)。
-
create_task适合长期后台任务(如心跳、日志轮转),但需自行跟踪和清理 -
TaskGroup适合有明确作用域的一组协同任务,比如批量请求、并行初始化、资源预热 - 如果你在
TaskGroup中启动任务后没 await 它,Python 会直接报RuntimeError: TaskGroup is not active
怎么正确使用 async with TaskGroup() 启动并等待多个协程?
核心就三步:进入上下文 → 调用 tg.create_task() → 自动等待全部完成。注意不能用 asyncio.create_task() 替代,否则任务脱离 TaskGroup 管理。
import asyncio
<p>async def fetch(url):
await asyncio.sleep(0.1)
return f"done {url}"</p><p>async def main():
async with asyncio.TaskGroup() as tg:
task1 = tg.create_task(fetch("<a href="https://www.php.cn/link/e75a2d435455f0626ccf0af67216e76f">https://www.php.cn/link/e75a2d435455f0626ccf0af67216e76f</a>"))
task2 = tg.create_task(fetch("<a href="https://www.php.cn/link/88b3febc5798a734026c82c1012408f5">https://www.php.cn/link/88b3febc5798a734026c82c1012408f5</a>"))</p><h1>✅ 正确:task1 和 task2 都受 tg 生命周期约束</h1><pre class="brush:python;toolbar:false;"># 此处 task1.result() 和 task2.result() 已可安全调用
print(task1.result(), task2.result())asyncio.run(main())
-
tg.create_task()返回的是asyncio.Task实例,和create_task返回类型一致,但语义不同 - 不要对
tg.create_task()的结果再做await——TaskGroup已隐式 await 所有任务 - 如果某个任务 raise 异常,其他任务会被取消,且该异常会重新抛出(除非用
except捕获)
遇到 CancelledError 或 “TaskGroup is closed” 错误,通常是因为什么?
这类错误几乎都源于作用域错位或跨上下文引用任务:
在
async with TaskGroup()块外访问其创建的Task对象的result()或exception(),会触发RuntimeError: TaskGroup is closed如果在
TaskGroup内部 await 一个已被取消的任务(比如因其他任务失败而被连带取消),会收到asyncio.CancelledError忘记
async with,直接TaskGroup()实例化,会导致对象未激活,后续create_task失败确保所有
tg.create_task()调用都在async with块内不要在
TaskGroup退出后检查任务状态;如需容错,应在块内用try/except包裹单个任务若需部分失败仍继续,应把逻辑拆到独立协程中,而非依赖
TaskGroup的默认行为
TaskGroup 在 Python 3.11+ 中的兼容性与替代方案
TaskGroup 是 Python 3.11 新增的标准库特性,位于 asyncio 模块下,无需额外安装。它替代了早期社区广泛使用的 anyio.TaskGroup 或 trio.Nursery,但语义更接近后者。
- Python asyncio.gather(return_exceptions=True) + 手动 cancel 逻辑
-
asyncio.gather不提供自动取消传播,出错后其余任务继续运行,容易掩盖问题 - 即使在 3.11+,也不要滥用
TaskGroup去包裹单个任务——它本意是“一组”,不是“一个”的语法糖
真正需要关注的是:你是否在用它管理有共同成败语义的任务集合。如果不是,可能只是需要一个 create_task 或 gather。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











