asyncio.run() 不能嵌套调用,因其专为顶层入口设计,会自动创建并关闭事件循环;若当前线程已有运行中的事件循环(如在 async 函数或已启动的 run() 中),再次调用将触发 RuntimeError。

会抛出 RuntimeError: asyncio.run() cannot be called from a running event loop 错误。
为什么不能嵌套调用 asyncio.run()
asyncio.run() 的设计目标是作为程序的**顶层入口**,它会自动创建一个新的事件循环、运行协程、等待完成,然后关闭循环。如果当前线程已经有一个正在运行的事件循环(比如你已经在某个 async 函数里,或已在 asyncio.run() 启动的上下文中),再次调用 asyncio.run() 就会冲突。
常见触发场景:
- 在 async 函数内部直接写
asyncio.run(another_coro()) - 在 Jupyter Notebook 单元格中多次运行
asyncio.run(...)(尤其在未重启内核时) - 在已由 asyncio.run() 启动的协程中,又试图启动另一个独立的 run()
正确替代方案:用 await 代替嵌套 run()
如果你已在异步环境中(比如另一个协程里),应该直接 await 目标协程,而不是用 asyncio.run() 包裹它:
❌ 错误写法:
async def inner():
return "done"
async def outer():
这里会报错!
result = asyncio.run(inner()) # RuntimeError
return result
✅ 正确写法:
async def inner():
return "done"
async def outer():
直接 await,复用当前事件循环
result = await inner()
return result
顶层才用 asyncio.run
asyncio.run(outer())
需要“启动新异步任务”?用 create_task 或 ensure_future
如果本意不是等待结果,而是想并发执行另一个协程(比如发个后台任务),应使用 asyncio.create_task():
-
asyncio.create_task(coro):立即调度协程,在后台运行,返回 Task 对象 -
await task可等待其完成;不 await 也不影响它运行(但要注意生命周期) - 避免用
asyncio.run()模拟“多线程式”启动——asyncio 是单线程并发,靠事件循环调度
特殊情况:子进程或线程中运行 asyncio.run()
如果你真需要隔离的事件循环(例如在 ThreadPoolExecutor 中执行阻塞 IO 后再跑一段异步逻辑),可以在线程内调用 asyncio.run() —— 因为每个线程默认没有事件循环。但要注意:
- 不能在主线程的 asyncio.run() 内部的线程里再调用 asyncio.run()(除非明确新建线程)
- 这种做法较重,通常应优先考虑用
loop.run_in_executor或重构为纯 await 链路









