Skip to content

实验 7:一组任务一起收尾

上一节只处理一个任务超时。现在看一组任务:如果其中一个失败,剩下的任务还要继续跑吗?

很多业务里不应该继续。比如构造一个页面时,主请求已经失败,相关的补充请求也该停掉。这就是 TaskGroup 好用的地方。

运行:

bash
python3 examples/asyncio_demos/07_taskgroup_failure.py

TaskGroup 的规则

示例里开了三个子任务:

python
async with asyncio.TaskGroup() as tg:
    tg.create_task(call_service("search", 0.1, fail=True))
    tg.create_task(call_service("audit", 1.0))
    tg.create_task(call_service("metrics", 0.8))

search 会先失败。TaskGroup 发现子任务抛异常后,会取消还没结束的兄弟任务,然后等它们执行清理代码。

裸 create_task 有什么问题

如果你这样写:

python
asyncio.create_task(call_service("audit", 1.0))

这件事就离开了当前代码块。它失败了谁处理?当前请求结束了它还该不该跑?这些问题都要你自己管。

TaskGroup 把一组任务放进同一个 async with。代码块结束时,这组任务也有明确结果:要么都完成,要么失败并收拾干净。

ExceptionGroup 是什么

TaskGroup 可能同时收集多个异常,所以外面用:

python
except* RuntimeError as group:
    print(len(group.exceptions))

这里先记住用法即可。重点是:子任务失败不会悄悄丢在后台。

小练习

  1. searchfail=True 改成 False,观察三个任务是否都正常完成。
  2. audit 的 delay 改成 0.05,让它先完成,再看 search 失败时谁会被取消。
  3. call_service 里把 except asyncio.CancelledError 后面的 raise 删除,观察 auditmetrics 看起来像“自己正常结束”还是“被取消后清理”。这个练习是为了说明:清理可以做,但取消信号通常要继续传出去。

面向学习目的的 Python asyncio 中文教程与 mini_asyncio 教学运行时。