Python 3.10+ 中 asyncio.get_event_loop() 被废弃,因它不再自动创建事件循环,仅获取已设置的循环,未设置时抛 RuntimeError 或 DeprecationWarning;应改用 asyncio.get_running_loop()、asyncio.new_event_loop() 或 asyncio.run()。

Python 3.10+ 中 asyncio.get_event_loop() 报 DeprecationWarning 或直接抛 RuntimeError,不是代码写错了,是旧调用方式被明确废弃了。
asyncio.get_event_loop() 在 3.10+ 为什么失效
Python 3.10 起,asyncio.get_event_loop() 的行为被大幅收紧:它不再自动创建默认事件循环,而只尝试获取「已存在且已设置」的循环。如果当前线程没运行过 loop(比如你在普通函数里直接调),就会触发 RuntimeError: There is no current event loop;在 3.10–3.12 早期版本中则先发 DeprecationWarning,3.13+ 已完全移除该回退逻辑。
根本原因是 asyncio 推动「显式优于隐式」——你得自己决定是复用、新建,还是用高层封装。
- 在协程内部或回调中,应改用
asyncio.get_running_loop()(仅限已运行的上下文) - 在主线程启动前、或需要独立隔离的场景,应显式调用
asyncio.new_event_loop()并手动set_event_loop() - 绝大多数脚本入口,直接用
asyncio.run()即可,它会自动管理整个生命周期
asyncio.run() 是什么情况下不能用
asyncio.run() 看似万能,但它有硬性限制:只能调用一次,且必须在主线程顶层调用。一旦你遇到以下任一情况,就不能依赖它:
- 已有主事件循环在运行(如 Jupyter、FastAPI、Tornado、aiohttp 的 app.run() 启动后)
- 需要从另一个 OS 线程中调度协程(比如后台线程触发异步通知)
- 想复用同一个 loop 执行多个不相关的协程批次(避免反复创建销毁开销)
- 嵌入到 C 扩展或某些 GUI 框架(如 PySide6 的
QEventLoop)中,需接管控制权
此时你必须手动管理 loop:用 asyncio.new_event_loop() 创建,再通过 loop.run_until_complete() 或 loop.run_forever() 驱动,但务必注意线程绑定——loop 与创建它的线程强绑定,跨线程调用 run_in_executor 以外的方法会出错。
多线程中调度协程的正确姿势
从非主线程(比如 threading.Thread)里触发协程,不能直接 await 或调 loop.create_task(),因为 loop 不在当前线程。常见错误包括:
- 在子线程里调
asyncio.get_event_loop()→ 报No current event loop - 拿到主线程的 loop 后直接
loop.create_task()→RuntimeError: Non-thread-safe operation invoked on an event loop other than the current one
正确做法是使用线程安全接口:
- 调度普通回调:用
loop.call_soon_threadsafe(callback, *args) - 调度协程对象:用
asyncio.run_coroutine_threadsafe(coro, loop),返回concurrent.futures.Future - 执行阻塞操作:用
loop.run_in_executor(executor, blocking_func)
注意:loop 必须来自主线程(通常是 asyncio.get_event_loop() 或 asyncio.get_running_loop()),且不能是临时新建的。
调试时容易忽略的 loop 生命周期陷阱
即使语法全对,loop 的状态也极易导致静默失败或资源泄漏:
- 手动创建的
asyncio.new_event_loop()不会自动关闭,必须显式调loop.close(),否则可能引发ResourceWarning或进程无法退出 -
asyncio.run()内部会自动调loop.close(),但如果你中途用sys.exit()或未捕获异常退出,关闭逻辑可能跳过 - 在 Jupyter 中多次运行含
asyncio.run()的 cell,第二次会报RuntimeError: asyncio.run() cannot be called from a running event loop,此时应改用await或get_running_loop().create_task() - 启用调试模式(
asyncio.run(main(), debug=True))能暴露“未 await 的协程”和慢回调,但不会帮你修复 loop 绑定问题
最稳妥的做法,是把 loop 获取逻辑下沉到真正需要它的最小作用域,并始终优先用 get_running_loop() 替代 get_event_loop() —— 它不造轮子,只查当前正在跑的那个,错就是真错,不给你模糊地带。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











