taskgroup 不能用于初始化包,因其仅支持并发执行异步任务,而包初始化(如 __init__.py 执行)是同步且不可并发的 import 过程;正确用法是分离导入与初始化,将各模块的 async 初始化函数(如 init()、setup())交由 taskgroup 并发调度。

Task Groups 在 Python 3.11 中不能用于“初始化包”
Python 3.11 的 asyncio.TaskGroup 是为并发执行 *异步任务* 设计的,不是用来“初始化包”或触发模块导入的。包初始化(比如 __init__.py 执行、全局变量设置、C 扩展加载)是同步过程,发生在 import 时,且通常只执行一次。试图用 TaskGroup 去“并行初始化”多个包,既无必要,也不可行——import 本身不是协程,不能被 asyncio.create_task() 包装。
你真正想解决的可能是:并发加载多个模块的异步资源
常见真实场景是:多个模块各自封装了需要 await 的初始化逻辑(如连接数据库、拉取配置、启动子服务),而你想让它们并发启动,避免串行等待。这时 asyncio.TaskGroup 才有用武之地。
-
import语句本身仍需在async函数外或内同步执行(它不阻塞事件循环) - 真正可并发的是各模块暴露的异步初始化函数,比如
await module_a.init()、await module_b.setup() - 必须确保这些函数是真正的协程(用
async def定义),而非普通函数
示例:
import asyncio import module_a import module_b <p>async def main(): async with asyncio.TaskGroup() as tg: tg.create_task(module_a.init()) # 假设返回协程 tg.create_task(module_b.setup()) # 同上 </p>
误用 TaskGroup 会触发 RuntimeError 或静默失败
如果把同步函数(如 module_c.load_config())直接传给 tg.create_task(),会报错:RuntimeError: a coroutine was expected, got ...。更隐蔽的问题是:有人试图在 TaskGroup 里做 import,以为能加速——但 import 是同步的,且受 CPython 导入锁保护,实际仍是串行,还可能因竞态导致 ImportError 或模块状态不一致。
- 不要在
async with asyncio.TaskGroup()块内写import xxx - 不要对普通函数调用结果(非协程对象)调用
create_task() - 若模块初始化含阻塞 I/O(如读大文件),应先用
loop.run_in_executor()包装,再交给TaskGroup
替代方案:按需导入 + 并发执行初始化逻辑
正确做法是分离“导入”和“初始化”。导入放前面(同步、一次),初始化逻辑提取为协程,再并发调度。
- 所有
import放在模块顶层,或至少放在async def外 - 每个包提供明确的异步入口,如
async def startup() - 用
TaskGroup管理这些startup()调用,它会自动处理异常传播和取消 - 注意:若某个初始化失败,整个
TaskGroup会 cancel 其余任务——这是设计特性,不是 bug
关键点在于,TaskGroup 管理的是“运行中的协程”,不是“模块加载时机”。Python 的导入机制本身不支持并发初始化。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











