Python asyncio.TaskGroup 怎样在任务组结束时集中处理异常
将多个协程用TaskGroup.create_task加入任务组,在async with外层用except*捕获指定类型的异常子组。某个任务出现非取消异常后,TaskGroup会取消其余任务并等待它们结束,然后把已发生的非取消异常集中抛出;它不会为了收集所有业务错误而放任其余任务继续完成。
官方地址:https://www.python.org/
准备 Python 3.11 及以上环境
设想一个同时读取订单摘要和库存摘要的异步入口。如果由我维护这个入口,我会先明确:任何一项失败就让本次整体请求失败,还是允许各项独立失败。这里采用前一种约定,适合用TaskGroup。下面是为说明机制设计的本地模拟,未连接真实业务服务,也未在本机执行。
TaskGroup和except*从Python 3.11开始提供。保存示例为taskgroup_demo.py,使用Python 3.11及以上解释器,无需安装第三方库。不要把except*代码交给Python 3.10解析。

把任务与异常出口放在同一个作用域
把try放在async with外面才能覆盖退出任务组时抛出的异常。示例让订单任务抛出ValueError,库存任务进入可取消的等待;finally代表资源清理的位置。
import asyncio
async def load_summary(name, delay, invalid=False):
try:
await asyncio.sleep(delay) # 模拟可取消的异步等待
if invalid:
raise ValueError(f"{name}: 摘要格式错误")
return {"name": name, "items": 3}
finally:
# 实际项目在此关闭本任务持有的资源。
print(f"{name}: 清理结束")
def leaves(group):
# 子组可以继续嵌套,递归取得叶子异常。
for error in group.exceptions:
if isinstance(error, BaseExceptionGroup):
yield from leaves(error)
else:
yield error
async def main():
tasks = {}
try:
async with asyncio.TaskGroup() as group:
tasks["订单"] = group.create_task(
load_summary("订单", 0.02, invalid=True), name="orders"
)
tasks["库存"] = group.create_task(
load_summary("库存", 1.0), name="inventory"
)
except* ValueError as errors:
for error in leaves(errors):
print(f"输入问题: {error}")
else:
# 仅在任务组正常完成时读取全部结果。
print({key: task.result() for key, task in tasks.items()})
if __name__ == "__main__":
asyncio.run(main())
except* ValueError匹配异常组中的ValueError叶子,并保留子组结构,所以errors.exceptions不保证是扁平列表。辅助函数leaves只做遍历,便于逐条记录。本例没有用except* Exception吞掉所有未知问题。
任务组正常完成后才能直接按成功路径读取结果;若已经处理过异常,不能随后无条件对全部任务调用result(),因为其中可能有失败或被取消的任务。
运行时观察取消与异常分组
读者可运行以下命令:
python3 taskgroup_demo.py预期会看到任务清理消息和“输入问题”消息,而不会打印整批成功结果。输出行的具体顺序与调度有关,不应据此推导任务执行顺序;这里提供的是阅读判断标准,没有提供伪造的实测输出。
| 发生的情况 | 组退出时的含义 |
|---|---|
| 所有任务成功 | 正常离开async with,可读取结果 |
| 一个任务抛ValueError | 其余未完成任务被取消,等待退出后抛异常组 |
| 多个任务在取消生效前已经失败 | 已发生的非取消异常可共同进入异常组 |
| 任务因组内取消而结束 | CancelledError通常不作为普通失败加入异常组 |
集中处理并不保证收集到每个任务原本可能产生的错误。库存任务可能在到达自己的业务检查之前就已取消。若需求是每项都独立完成并形成逐项结果,应在任务内部把预期业务失败转换为明确结果对象,而不是误用TaskGroup的失败即取消语义。

扩展实验:保留未知异常和部分结果
可以把订单任务的ValueError改成RuntimeError,理解未知异常会继续向上传播。若组内同时存在ValueError与其他未匹配异常,except*只处理匹配部分,剩余部分仍会抛出。不要用裸except把外层请求伪装成成功。
另一个实验是给多个任务设置相近延迟并让它们分别失败。实际能收集多少个异常取决于失败与取消的时机,不能依赖固定数量或固定排序,也不应根据exceptions列表的位置反推任务身份。业务异常消息、附加字段或任务侧日志应携带自己的业务标识。
如果确实要保留部分成功结果,在处理完异常之后逐个判断task.cancelled(),再检查task.exception(),最后才读取task.result()。此时TaskGroup已经等待组内任务结束,判断应发生在组退出之后。部分成功如何对外返回仍是业务接口约定,不能靠捕获异常自动决定。
TaskGroup只管理通过该组create_task创建的任务。若子协程另用asyncio.create_task生成游离任务,不能假设它也会被当前组完整管理。
退出任务组后的清理与常见问题
资源释放放进finally或异步上下文管理器。若显式捕获asyncio.CancelledError做清理,通常应在清理后重新raise;吞掉取消可能干扰TaskGroup的结构化并发行为。CancelledError继承BaseException,普通except Exception不会捕获它。
为什么只有一个失败也会进入except*?
TaskGroup退出时可以把单个普通失败包装成异常组;except*面对的不是“必须至少两个错误”的特殊情况。
能否在同一个try中同时写except和except*?
不能。同一try的处理分支不能混用两种语法,需要嵌套try安排不同边界。except*分支内部也不能使用return、break或continue。
KeyboardInterrupt也会变成普通异常组吗?
KeyboardInterrupt和SystemExit有特殊规则:任务组会取消并等待其他任务,然后重新抛出原始异常。外部取消也不是应当随手忽略的业务失败。
async with内部主体抛错怎么办?
组主体的非取消异常也会触发取消与等待,并可能与任务异常一起被分组。把捕获边界放在整个async with外侧可以覆盖这一出口。
本文只用本地协程与标准库,实验结束后无需清理外部服务。真正接入网络客户端时,每个客户端、连接或事务仍应有明确的释放与失败语义。
Java CRC32C 怎样计算分块数据的校验值
- 上一篇
- Java CRC32C 怎样计算分块数据的校验值
- 下一篇
- Java 模块系统怎样导出只读 API 包
-
- 文章 · python教程 | 1小时前 | 文件处理 · 标准库 · python · Python 编码 文本流 TextIOWrapper reconfigure
- Python TextIOWrapper.reconfigure 怎样在不重开文件时切换编码
- 276浏览 收藏
-
- 文章 · python教程 | 1小时前 | python · pathlib · Python pathlib 目录边界 Path.is_relative_to 路径判断
- Python pathlib.Path.is_relative_to 怎样判断路径是否位于指定目录
- 473浏览 收藏
-
- 文章 · python教程 | 1小时前 | 正则表达式 · python · Python re 命名分组 Match.groupdict
- Python re.Match.groupdict 怎样读取命名分组
- 488浏览 收藏
-
- 文章 · python教程 | 1小时前 | python · pathlib · Python pathlib Path.rglob
- Python pathlib.Path.rglob 怎样排除构建目录
- 461浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python csv.DictReader 自定义 fieldnames 读取无表头文件
- 257浏览 收藏
-
- 文章 · python教程 | 1小时前 |
- Python functools.cache 怎样判断是否适合缓存无参函数
- 419浏览 收藏
-
- 文章 · python教程 | 1小时前 | TLS · python · 网络安全 · Python ssl.SSLContext TLS版本 minimum_version maximum_version
- Python ssl.SSLContext 怎样限制允许的 TLS 版本
- 399浏览 收藏
-
- 文章 · python教程 | 1小时前 | python · 文件系统 · Python 文件遍历 DirEntry os.scandir
- Python os.scandir 怎样减少目录遍历中的属性查询
- 353浏览 收藏
-
- 文章 · python教程 | 15小时前 | 并发 · 数组 · python · Python multiprocessing shared_memory 进程间数组
- shared_memory 怎样共享进程间数组
- 137浏览 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 543次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 516次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 500次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 485次学习
-
- PubMedQA
- 深入了解PubMedQA生物医学问答数据集,涵盖其核心功能、使用方法及在临床决策、药物研发等场景的应用,助力提升NLP模型性能。
- 697次使用
-
- H2O EvalGPT
- H2O EvalGPT是H2O.ai推出的开源LLM评估平台,提供详细的大模型性能排行榜、行业特定基准测试及A/B测试功能,助您快速选择最适合项目的高性能大语言模型。
- 707次使用
-
- LMArena
- LMArena是加州大学伯克利分校推出的AI模型匿名评测平台。通过盲测投票机制,用户可对比不同大模型回答并生成实时排行榜,助力开发者优化模型及用户选择最佳AI工具。
- 777次使用
-
- HELM
- 深入了解斯坦福推出的HELM(Holistic Evaluation of Language Models)大模型评测体系。本文解析其核心功能、安装配置步骤及应用场景,涵盖准确性、公平性、鲁棒性等多维度指标,助力开发者全面优化语言模型性能。
- 738次使用
-
- MMBench
- MMBench是由上海人工智能实验室等机构联合推出的多模态基准测试平台,提供细粒度能力评估、大规模数据集及VLMEvalKit工具。本文详细介绍其核心功能、安装使用方法及应用场景,助力开发者全面评估多模态模型性能。
- 571次使用
-
- go格式“占位符”输入输出 类似python的input
- 2023-01-19 346浏览
-
- Golang如何调用Python代码详解
- 2023-01-07 235浏览
-
- HTTP 的 response 中的响应体和头部是分开发送的吗?
- 2023-01-28 387浏览
-
- B站等视频网站的弹幕用的是 websocket 还是轮询?
- 2023-02-16 447浏览
-
- Linux 下有什么命令行工具以时序显示 CPU 占用率?
- 2023-01-13 360浏览

