asyncio.run() 后调用 asyncio.get_event_loop() 报错,因其内部创建并显式关闭事件循环,get_event_loop() 返回已关闭的旧循环,导致后续操作抛出 runtimeerror: event loop is closed。

为什么 asyncio.run() 后再调用 asyncio.get_event_loop() 会报错
因为 asyncio.run() 内部会创建新事件循环、运行协程、然后**显式关闭并丢弃该循环**。之后再调用 asyncio.get_event_loop(),它返回的仍是那个已被关闭的旧循环(而非新建一个),导致后续 loop.create_task() 或 loop.run_until_complete() 直接抛出 RuntimeError: Event loop is closed。
常见触发场景:在 Jupyter Notebook 中多次运行含 asyncio.run() 的单元格;或封装异步函数时误以为“获取循环就能复用”。
- ✅ 正确做法:每个顶层异步入口都用
asyncio.run(),不要手动取 loop - ❌ 错误写法:
asyncio.run(some_coro())<br>loop = asyncio.get_event_loop() # 这里 loop 已关闭<br>loop.run_until_complete(another_coro())
- ⚠️ 注意:
asyncio.get_event_loop()在 Python 3.10+ 默认行为已变,但关闭后的循环仍不可用
在已关闭的 loop 上调用 create_task() 怎么办
本质是试图往一个“已归还给操作系统”的资源里塞任务——这不可能成功。关键不是“怎么恢复 loop”,而是**避免落到这一步**。
典型错误模式:把 asyncio.run() 当成 setup/teardown 的一部分,却在外部保留了对 loop 的引用。
- ✅ 替代方案:用
asyncio.new_event_loop()+set_event_loop()手动管理(仅限高级场景)loop = asyncio.new_event_loop()<br>asyncio.set_event_loop(loop)<br>try:<br> loop.run_until_complete(main())<br>finally:<br> loop.close()
- ✅ 更安全的做法:所有异步逻辑都包裹在单次
asyncio.run()内,不暴露 loop - ⚠️ 不要尝试
loop.is_closed()后调用loop.run_forever()—— 已关闭的 loop 无法重启
Jupyter 中反复执行 async 代码时如何避免
Jupyter 的 cell 执行机制会让全局 event loop 状态变得不可预测。每次运行 asyncio.run() 都会关闭前一个 loop,但内核可能仍持有旧引用。
根本解法不是修 loop,而是绕过它。
- ✅ 推荐:用
await直接执行协程(前提是当前环境支持,如 IPython 7.0+)await some_coro()
- ✅ 次选:每次执行前强制重置(仅调试用)
import asyncio<br>asyncio.set_event_loop(asyncio.new_event_loop())
- ⚠️ 避免:
asyncio.get_event_loop().run_until_complete(...)—— 在 notebook 里极易踩坑 - ? 提示:检查是否启用了
nest_asyncio(pip install nest_asyncio,然后nest_asyncio.apply()),它能修补 notebook 的 loop 嵌套问题
第三方库内部触发 "Event loop is closed" 怎么定位
不是你的代码直接操作 loop,而是某库(比如 aiohttp、httpx、aiomysql)在 shutdown 阶段尝试清理连接时,发现 loop 已关 —— 这说明你提前结束了 loop,但没等库完成 cleanup。
典型表现:程序退出前出现该错误,且堆栈指向库内部的 __aexit__ 或 close()。
- ✅ 必做:确保所有 async context manager 正确 await,例如
async with aiohttp.ClientSession() as session:<br> await session.get(url)
- ✅ 显式 close 资源:若手动创建 client,退出前 await 其
close()方法 - ⚠️ 常见疏漏:在
asyncio.run()外围加了try/finally,但 finally 里调用了需要 loop 的 cleanup 逻辑
真正麻烦的从来不是“怎么 reopen loop”,而是谁在什么时候悄悄关掉了它,又没通知依赖它的模块。查调用链比修错误更有效。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











