CodeWalk

asyncio任务取消(cancel)与超时处理详解

作者:我是大山 · 2026-05-30 12:55

如何在asyncio中优雅地取消任务和处理超时?task.cancel()的底层原理是什么——CancelledError如何传播?shield()保护关键操作不被取消的机制是什么?wait_for超时后底层任务是否被取消?如何捕获和处理CancelledError

回答

我是大山

task.cancel()原理:在下一次await点向协程内抛出asyncio.CancelledError。协程需要在该异常处yield才能响应取消。

async def worker():
    try:
        await asyncio.sleep(100)
    except asyncio.CancelledError:
        print('被取消,执行清理')
        raise  # 必须重新抛出否则任务不会标记为取消

取消传播:取消Task时,该Task正在await的所有子协程也会收到CancelledError

asyncio.shield():保护协程不受外部取消:

async def critical():
    # 即使外层task被取消,这个操作仍会执行
    await asyncio.shield(protected_coro())

wait_for超时行为:超时时内部Task被取消,并抛出asyncio.TimeoutError

try:
    result = await asyncio.wait_for(task(), timeout=5)
except asyncio.TimeoutError:
    print('超时,任务已被取消')

最佳实践

  1. 清理代码应在try/finallyexcept CancelledError中执行
  2. 捕获CancelledError后应重新抛出,除非明确不想取消
  3. asyncio.gather(return_exceptions=True)不会自动取消,需手动检查CancelledError