Skip to content

实验 6:单个任务超时

真实 I/O 不能无限等。一个接口 200ms 内没回来,你可能就要给用户降级结果,或者换备用服务。

这一节只看一个任务超时,不碰 TaskGroup

运行:

bash
python3 examples/asyncio_demos/06_timeout_cancel.py

timeout 做了什么

示例代码:

python
try:
    async with asyncio.timeout(0.2):
        result = await slow_report()
except TimeoutError:
    print("main: timed out")

slow_report() 里会等待 1 秒。外层只给它 0.2 秒,所以到点后会发生三件事:

CancelledError 要重新抛出

示例里这样写:

python
except asyncio.CancelledError:
    print("slow_report: got cancel request")
    raise
finally:
    print("slow_report: cleanup")

CancelledError 是 asyncio 用来通知协程“该停了”的异常。你可以在这里打日志、关连接、释放资源,但通常要 raise 回去。否则外层可能以为任务正常结束了。

finally 为什么会执行

取消不会把函数硬切掉。它更像一次异常:协程在等待点醒来时收到 CancelledError,然后正常执行 finally

所以资源清理要放在 finally 里:

python
try:
    ...
finally:
    writer.close()
    await writer.wait_closed()

小练习

  1. timeout(0.2) 改成 timeout(2),确认任务会正常完成。
  2. 删除 except asyncio.CancelledError 里的 raise,你会发现外层不再打印 main: timed out。这说明取消信号被里面吞掉了。
  3. finally 里加一行 await asyncio.sleep(0.1),确认清理代码也可以包含异步等待。

面向学习目的的 Python asyncio 中文教程与 mini_asyncio 教学运行时。