Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

asyncio.gather 已拋錯但兄弟任務仍在跑?選擇 TaskGroup 或明確取消

gather傳播第一個例外但不取消兄弟任務。需要一起失敗時用TaskGroup;選擇性策略則持有Task、取消並等待清理。

選擇TaskGroup一起失敗或明確持有Task進行選擇性取消的決策圖。
原創插畫:先決定失敗政策,再選asyncio協調原語。 Watch at Ease

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. 驗收協作式取消

CancelledError在await點送入;以try/finally清理並通常重新拋出。

驗證gather繼續、TaskGroup取消等待、手動耗盡和父任務取消,並檢查副作用。

gather先拋錯、兄弟任務後完成及延遲cancel回傳false的時間線。
原創技術插畫:聚合Future完成後取消無效,必須等待子任務清理。 Watch at Ease