asyncio.wait_for超时后直接取消任务而非暂停,会触发cancellederror;须确保协程含可中断await调用,避免资源泄漏,推荐改用asyncio.timeout上下文管理器。

asyncio.wait_for 会直接取消超时任务,不是“暂停等一会儿”
很多人误以为 asyncio.wait_for 是给任务加个“倒计时提醒”,实际它会在超时后调用 task.cancel() —— 也就是触发 CancelledError。这意味着:任务必须能响应取消(比如在 await 点被中断),否则可能卡住或资源泄漏。
常见错误现象:asyncio.wait_for 返回超时异常,但后台任务仍在运行,数据库连接没关、HTTP 请求没终止、文件句柄未释放。
- 务必确保被包裹的协程内部有可中断的
await调用(如await asyncio.sleep()、await aiohttp.ClientSession.get()) - 避免在
wait_for中包裹纯 CPU 密集型同步代码(如time.sleep()或大循环),它不会被取消 - 若需清理,应在协程中捕获
asyncio.CancelledError并手动 close/release
timeout 参数为 None 时行为与 Python 3.10 不同
Python 3.11 中,asyncio.wait_for(coro, timeout=None) 等价于直接 await coro,不再抛出 TypeError。这是向后兼容的改进,但要注意:如果你依赖旧版报错来兜底,升级后逻辑可能悄然变化。
使用场景:动态超时控制(例如根据请求头传入 X-Timeout,缺省时设为 None)。
- 显式写
timeout=None比不传参数更清晰,避免歧义 - 不要依赖
timeout=None触发异常来做流程分支 - 若需统一处理“无超时”和“有超时”,建议提前判断并分流,而非全靠
wait_for
嵌套 wait_for 可能导致 CancelledError 被吞掉
当一个协程里多次用 asyncio.wait_for,且外层超时先触发,内层又正在等待另一个子任务时,CancelledError 可能被内层 wait_for 捕获并转化为 TimeoutError,从而掩盖原始取消原因。
示例:外层 wait_for(task_a, timeout=1),而 task_a 内部又调用了 wait_for(task_b, timeout=5) —— 若 1 秒到,task_a 被取消,但 task_b 的 wait_for 可能还没反应过来,反而抛出 TimeoutError 而非 CancelledError。
- 优先用单层
wait_for包裹整个顶层协程,避免嵌套 - 若必须分层超时,改用
asyncio.create_task()+asyncio.shield()控制取消传播 - 调试时加
try/except CancelledError在关键协程入口,确认是否被正确传递
与 asyncio.timeout 上下文管理器的区别在哪
asyncio.timeout(Python 3.11 新增)是更现代、更推荐的替代方案,它不返回新 awaitable,而是通过上下文管理器自动注入取消逻辑。
关键差异:
-
wait_for返回的是一个新 awaitable,需显式await;asyncio.timeout需搭配async with使用,作用域更明确 -
timeout管理器在退出时自动处理取消,对嵌套 await 更友好,不易丢CancelledError -
wait_for支持传入已存在的Task对象;timeout只能用于当前协程内的await表达式
简单迁移示例:
<pre class="brush:php;toolbar:false;"># 旧写法
try:
result = await asyncio.wait_for(fetch_data(), timeout=3)
except asyncio.TimeoutError:
log("fetch timed out")
<h1>新写法(推荐)</h1><p>try:
async with asyncio.timeout(3):
result = await fetch_data()
except TimeoutError: # 注意:这里是 TimeoutError,不是 asyncio.TimeoutError
log("fetch timed out")</p>真正难处理的不是语法,而是超时后任务状态的一致性——比如 HTTP 请求已发出但响应未收全,数据库事务已开始但未提交。这些地方没法靠 wait_for
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











