asyncio.gather() 默认一异常即中断,加 return_exceptions=True 可使异常作为对应位置返回值存入列表,保持并发执行;需用 isinstance(r, Exception) 判断成败,不适用于依赖型任务或自动重试。

asyncio.gather() 报错就中断?加 return_exceptions=True 就行
默认情况下,asyncio.gather() 只要有一个协程抛异常,整个调用就立刻失败,其余还在跑的协程会被取消——这不是你想要的“并发执行+容错”,而是“一损俱损”。加 return_exceptions=True 后,异常不会往外冒,而是作为对应位置的返回值原样塞进结果列表里,后续逻辑可以自己判断处理。
- 必须显式传参,不写就是
False,没得商量 - 返回值类型不变(还是
list),但里面可能混着Exception实例,不是所有元素都保证是预期类型 - 别在
try/except里套整个gather()再加这个参数——那没意义;它本身就是为“不中断”设计的
怎么区分哪些成功、哪些失败?看返回值类型就行
return_exceptions=True 后,gather() 返回的列表和输入协程顺序严格一致。每个元素要么是正常结果,要么是 Exception 子类实例。靠 isinstance(x, Exception) 就能筛出来。
- 别用
if x is None或if not x判断失败——异常对象本身是非空、真值 - 如果协程本就可能返回
None,那就更不能靠“空值”判断,必须用类型检查 - 示例:
results = await asyncio.gather(coro_a(), coro_b(), return_exceptions=True)<br>for i, r in enumerate(results):<br> if isinstance(r, Exception):<br> print(f"Task {i} failed: {r}")<br> else:<br> print(f"Task {i} succeeded: {r}")
常见误用:把 return_exceptions=True 当万能兜底
它只管“不让异常冒泡中断其他任务”,不负责重试、不自动恢复、不隐藏错误根源。如果某个协程反复抛 ConnectionError,加了这个参数只是让你拿到一堆异常对象,而不是问题消失。
- 网络请求类协程建议搭配
asyncio.timeout()或自定义重试逻辑,别光靠这个参数硬扛 - 如果某任务失败后,后续任务依赖它的输出,那即使加了
return_exceptions=True,业务逻辑仍可能崩——得提前设计 fallback 值或跳过逻辑 - 日志里打异常时,记得用
traceback.format_exception()而不是直接str(e),否则丢堆栈信息
和 asyncio.create_task() + await 手动收集的区别
手动 create_task 再逐个 await 确实也能捕获各自异常,但失去并发性保障:如果第一个 await 卡住,后面的任务哪怕早完成了也得干等。而 gather(..., return_exceptions=True) 是真并发等待全部完成。
立即学习“Python免费学习笔记(深入)”;
-
gather内部会统一调度,适合“一批独立任务,全都要结果”的场景 - 如果任务之间有依赖、或需要流式处理(比如一个完成就立刻消费),那
create_task+asyncio.as_completed()更合适 - 性能上无本质差异,但
gather更简洁;滥用as_completed配合大量try/except反而容易漏异常处理点







