asyncio.shield() 并非免疫取消,而是拦截外部取消信号,仅阻止取消传播至被包裹任务,但无法阻止其内部主动响应取消、子任务被取消、直接调用task.cancel()或超时机制触发的取消。
asyncio.shield() 不是“免疫取消”,而是“拦截取消信号”——它让外部调用 cancel() 看起来成功,但被 shield 包裹的协程或任务仍继续运行。
shield 仅阻断**来自外部的取消传播**,不改变内部行为:
asyncio.current_task().cancelled() 并响应退出,shield 无法阻止task.cancel(),任务仍会被取消asyncio.wait_for)触发的取消——因为 wait_for 内部会直接 cancel 它所包装的 Future,而 shield 只作用于你显式传入的对象层级这些情况会让 shield “失效”或产生误导:
await asyncio.shield(some_coro()
):每次 await 都新建协程实例,shield 只保护单次执行,无法延续到后续 await 链中task = asyncio.create_task(coro()); task.cancel(); shield = asyncio.shield(task) —— shield 会立即进入 cancelled 状态,且 await 它会立刻抛 CancelledError
gather 中 shield 部分子任务,但没设 return_exceptions=True:一旦其他未 shield 的任务出错或被取消,整个 gather 可能提前中断,shield 的任务虽在跑,却失去上下文协调shield 要起效,必须配合明确的任务生命周期控制:
task = asyncio.create_task(coro()),再 shield:shielded = asyncio.shield(task),后续统一 await 或传给其他协程try/finally 块中,或用 async with,shield 只是辅助,不能替代结构化异常处理shielded.cancelled(),而要检查其包裹的 task 是否真的在运行:task.done() is False and not task.cancelled()
shield 和超时机制不是同一层控制:
asyncio.timeout(5) 进入上下文后,会在超时时调用当前 task 的 cancel() —— shield 可以吸收这次调用,但前提是 shield 包裹的是该 task 本身,而不是它的某个 await 表达式contextvars.Context 或自定义取消信号时,shield 不感知也不拦截这些逻辑层面的退出请求,它只拦截事件循环对 Future 的 cancel 调用