在async函数中安全销毁异步资源需用try-finally兜底,资源变量声明于try外,finally中await关闭;优先用async with(需实现__aenter__/__aexit__);主动捕获cancellederror并重抛;服务退出时按依赖顺序超时清理。

在 async 函数中安全销毁异步资源,关键不是“等做完再关”,而是让释放逻辑不依赖执行路径——无论成功、出错还是被取消,资源都必须释放。
用 try-finally 做兜底保障
这是最基础也最可靠的模式。资源获取放在 try 外或开头,清理逻辑写在 finally 里,且必须用 await 执行关闭操作。
- 资源变量声明一定要在 try 块外部,否则 finally 访问不到
- finally 中的 await conn.aclose()、await file.close() 等不能省略,否则只是发起关闭,没等它完成
- 清理函数建议设计成幂等:多次调用不报错,避免重复 close 引发 RuntimeError
优先使用 async with 管理生命周期
只要类实现了 __aenter__ 和 __aexit__,就能自动处理获取和释放。
- __aenter__ 负责异步建连、加锁、打开文件等
- __aexit__ 接收异常信息,可判断是否发生了错误,并执行对应清理(比如回滚事务、释放锁)
- 返回 None 或 False 表示不压制异常;一般不要 return True,否则会吞掉错误,掩盖问题
主动响应任务取消
协程被 task.cancel() 中断时,会在下一个 await 点抛 CancelledError。仅靠 finally 不够,需显式捕获并清理。
- 在 try 块中 await 长耗时操作(如网络请求、数据库查询)
- except asyncio.CancelledError 中执行清理,完成后重新 raise,确保上层知道任务已取消
- finally 再补一层关闭动作,形成双重保险——防止 except 里漏掉某些资源
服务退出时统一协调清理
单个函数的 try-finally 解决不了全局资源泄漏。应用关闭阶段要主动介入。
- 监听 SIGTERM / SIGINT 信号,触发整体关闭流程
- 先停止接收新请求,再逐批等待/取消正在运行的协程
- 用 asyncio.wait_for 给清理加超时,避免某个连接卡住导致整个进程无法退出
- 按依赖顺序释放:比如先停消费任务,再关数据库连接,最后释放文件句柄或事件监听器











