RuntimeWarning: coroutine 'xxx' was never awaited 是协程对象被创建后未被 await、create_task 或 ensure_future 调度所致,仅在 GC 回收时触发,可用 python -Werror::RuntimeWarning 强制报错定位;常见于同步函数中误调异步函数、条件分支漏 await、列表推导式生成协程对象等场景。

协程对象没被 await、create_task 或 ensure_future 调度,就等于“只生不养”,Python 会创建它,但既不执行也不释放——这不是 bug,是设计行为。泄漏源头往往不是代码写错了,而是你根本没让它动起来。
RuntimeWarning: coroutine 'xxx' was never awaited 怎么快速定位
这个警告不是每次都会出现,只在协程对象被 GC 回收时触发,所以短脚本可能完全不报,而 FastAPI 每次请求漏一个 await 就稳稳复现。
- 用
python -Werror::RuntimeWarning script.py强制把警告当错误,程序立刻崩在漏await的那一行 - 常见藏匿点:
print(get_data())、logger.info("start", extra={"task": do_work()})、if cond: f() else: await f()(else 分支漏了) - 列表推导式里写
[fetch(u) for u in urls]→ 得到的是协程对象列表,不是结果;要并发执行得用await asyncio.gather(*[fetch(u) for u in urls])
同步函数里调用了 async 函数,怎么补救
不能直接加 await,因为当前函数不是 async。强行改会造成调用链全得改,不现实。
- 最外层入口(如
if __name__ == '__main__':)用asyncio.run(main())包一层,仅限此处 - 中间层同步函数想触发异步逻辑又不想等结果?必须显式转成任务:
asyncio.create_task(my_coro()),否则协程对象创建即丢,可能根本没执行 - 如果只是日志或调试中顺手调用,别传协程对象本身,改传描述性字符串,比如
extra={"coro_name": "fetch_user"},避免 logging handler 持有强引用
Task 创建后没管理,为什么内存不降
asyncio.create_task() 不等于“已托管”——它只是把协程扔进事件循环,之后就不管了。没引用、没 await、没 cancel,它就成了孤儿。
快速生成专业的 Python 脚本和应用代码。一键创建完整项目结构,支持CLI、API、爬虫、Bot、Django等多种项目类型,包含完整的项目结构、配置文件、依赖管理、测试、README和文档。
立即学习“Python免费学习笔记(深入)”;
- 务必保存 task 引用:放进
set、list或全局weakref.WeakSet(),否则连取消都做不到 -
task.cancel()只设标志,真正释放要靠协程体自己退出帧栈;卡在await asyncio.Lock.acquire()或await queue.get()就永远不释放 - 紧急时可清空私有属性(仅限调试):
task._exception = None、task._traceback = None,否则 traceback 持有整个协程帧链 - 检查
task.done()为True但task._coro.cr_frame非None,说明协程帧没清理,就是泄漏证据
为什么 all_tasks() 看不到泄漏,但 RSS 一直在涨
asyncio.all_tasks() 只返回“还活着”的 Task,而泄漏常发生在已完成却未被回收的 Task 上——它们被日志 extra、全局 dict、第三方库缓存等悄悄焊死了。
- 用
gc.get_referrers(task)查谁在强持有它,重点盯frame和extra字典 - 避免在 Task 内部直接引用大对象(如
pandas.DataFrame),改用 ID 或weakref.ref() - 所有
async with必须包try/except,否则异常一出,__aexit__不执行,连接池、缓冲区、临时文件句柄全滞留
协程泄漏最难缠的地方不在“找不到”,而在“以为找到了却漏掉另一半”:比如你 fix 了 await 缺失,但忘了 async with 里的异常路径,或者清掉了 Task 却没清理它闭包里捕获的 logger 实例。每一步都要手动验证,不能只看 len(asyncio.all_tasks()) 下降了就认为完事。

















