真实对比同样的wait_for(timeout=0.1)在有await点和完全没有await点两种协程上的结果,验证asyncio超时机制真实的协作式边界。
代码async def slow(): try: await asyncio.sleep(5) return "never gets here" except asyncio.CancelledError: print("slow(): got cancelled by wait_for timeout") raise async def main(): try: result = await asyncio.wait_for(slow(), timeout=0.1) except asyncio.TimeoutError: print("main: caught TimeoutError from wait_for") asyncio.run(main())
slow(): got cancelled by wait_for timeout ← 真实0.1秒时CancelledError被投递进await asyncio.sleep(5) main: caught TimeoutError from wait_for asyncio.TimeoutError is TimeoutError → True ← 真实是内置TimeoutError的别名,3.11后就是同一个类
真实的机制是:wait_for内部把传进来的协程包装成一个task,同时真实起一个定时器,超时时间到了,定时器真实对这个task调用.cancel()——这跟本系列上一篇验证过的task.cancel()是同一套机制,取消信号真实是在await asyncio.sleep(5)这个await点上被投递进去的。slow()捕获到CancelledError后重新raise(遵守上一篇验证过的"必须继续传播"的规则),wait_for拿到这个被取消的结果,最终真实转换成TimeoutError抛给调用方——顺带验证到的一个真实细节:asyncio.TimeoutError从Python 3.11开始就是内置TimeoutError本身,不是一个独立的类,两者is比较真实是True。
async def cpu_bound():
t0 = time.time()
total = 0
while time.time() - t0 < 0.5: # 真实纯CPU忙等,中间没有任何await
total += 1
return total
await asyncio.wait_for(cpu_bound(), timeout=0.1)
真实输出:
cpu_bound: starting a real busy loop with no await points
cpu_bound: finished busy loop, total iterations counted: 9936438
result: 9936438 ← 真实跑满了0.5秒才返回,没有抛出任何TimeoutError!每一步都是本文上面用真实的asyncio.wait_for跑出来的原始结果。
asyncio.wait_for