科技 · 实用指南
asyncio.gather 已抛错但兄弟任务仍在运行?选择 TaskGroup 或显式取消
gather传播首个异常但不会取消兄弟任务。需要一起失败时用TaskGroup;需要选择性策略时持有Task句柄、取消并等待清理。

asyncio.gather是聚合器,不是一起失败的作用域。首个异常到达调用者时,未完成的兄弟任务仍保持调度;此时gather Future可能已经完成,再调用cancel会返回false。
先决定失败策略。所有操作属于同一一致性边界时,在Python 3.11+使用TaskGroup;若只应停止部分任务,则显式创建Task、按策略取消、等待清理并重新抛出。
1. 证明失败后仍有工作
让一个协程快速抛错,另一个稍后写入标记。捕获gather异常后调用cancel并让循环继续;false加上标记就是延迟取消。
CPython 3.12.14实测中慢任务继续完成,而TaskGroup版本取消慢任务。
2. 先选策略再选API
共同更新一个逻辑结果或一个失败使其余无效时,用TaskGroup一起失败。
若任务独立或错误可恢复,保留Task所有权并显式选择。
3. Python 3.11+用TaskGroup
经同一TaskGroup建立兄弟任务;首个非取消异常会取消其余任务并等待清理。
在async with外用except*处理ExceptionGroup,不要吞掉CancelledError。
4. 选择性策略要持有、取消、等待、重抛
先create_task保留句柄,异常时只取消策略指定的任务,再用return_exceptions=True等待所有已拥有任务。
清理完成后重新抛出原错误,或明确编码每个结果。
5. 验收协作式取消
取消在await点注入CancelledError;以try/finally清理并通常重新抛出。
验证gather继续、TaskGroup取消等待、手动耗尽任务和父任务外部取消,并核对副作用日志。
