“RuntimeError: asyncio.run() cannot be called from a running event loop” 是在 Jupyter 和 async 框架里调用异步库时最常见的报错,网上常见的答案是装 nest_asyncio。这篇在本机把它复现出来,看清楚为什么,以及不装任何补丁时有哪些正确写法,顺带把几个长得像的 asyncio RuntimeError 一起测了。
在 async def 里调用 asyncio.run(inner())(退出码 1):
Traceback (most recent call last):
RuntimeError: asyncio.run() cannot be called from a running event loop
<sys>:0: RuntimeWarning: coroutine 'inner' was never awaited
在 async def 里调用 loop.run_until_complete(inner())(退出码 1):
Traceback (most recent call last):
RuntimeError: This event loop is already running
<sys>:0: RuntimeWarning: coroutine 'inner' was never awaited
被 async 代码调用的普通函数里调用 asyncio.run()(最常见:库的同步封装)(退出码 1):
Traceback (most recent call last):
RuntimeError: asyncio.run() cannot be called from a running event loop
<sys>:0: RuntimeWarning: coroutine 'inner' was never awaited
忘了括号:asyncio.run(main)(退出码 1):
Traceback (most recent call last):
TypeError: An asyncio.Future, a coroutine or an awaitable is requiredasyncio.run 要新建并运行一个事件循环,一个线程里同一时刻只能有一个在跑。async 代码、Jupyter、asyncio REPL 里都已经有。
python -m asyncio 里依次输入 await inner() 和 asyncio.run(inner())(退出码 0):
>>> >>> >>> 42
>>> >>> asyncio REPL 3.15.0 (main, Oct 9 2026, 11:16:41) [Clang 21.0.0 (clang-2100.3.34.2)] on darwin
Use "await" directly instead of "asyncio.run()".
Type "help", "copyright", "credits" or "license" for more information.
>>> import asyncio
Traceback (most recent call last):
RuntimeError: asyncio.run() cannot be called from a running event loop
exiting asyncio REPL...直接在顶层 await,不用 asyncio.run。
四种写法(退出码 0):
await inner(1) -> 2,0.20 s
gather 三个 -> [2, 4, 6],0.20 s(并发,约一个的时间)
create_task 再 await -> 10,0.20 s
asyncio.to_thread(sync_wrapper, 7) -> 14,0.20 s(线程里 asyncio.run 能用)
5 个线程各自 asyncio.run -> [0, 2, 4, 6, 8],0.21 s能 await 就 await;并发用 gather / create_task;必须调用自带 asyncio.run 的同步封装时放到线程里。
run_sync 封装(退出码 0):
同步代码里调用 -> 2
async 代码里(会阻塞这个循环)调用 -> 11
没有运行中的循环时 get_running_loop() -> RuntimeError('no running event loop')
注意:在 async 代码里这样调用,会让当前事件循环被阻塞到那个协程结束(上面第二行),只是不再报错;能 await 就别这样写先判断有没有运行中的循环再决定;在 async 里这样调用仍会阻塞当前循环。
在事件循环外(退出码 0):
asyncio.create_task() 在循环外 -> RuntimeError('no running event loop')
asyncio.get_running_loop() 在循环外 -> RuntimeError('no running event loop')
asyncio.get_event_loop() 在循环外、没设置过循环 -> RuntimeError("There is no current event loop in thread 'MainThread'.")
<tmp>/s8.py:5: RuntimeWarning: coroutine 'inner' was never awaited
except RuntimeError as e: print('asyncio.create_task() 在循环外 ->', repr(e))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
循环已关闭(退出码 0):
关闭后的循环再 run_until_complete -> RuntimeError('Event loop is closed')
asyncio.run() 结束后,它用的循环 is_closed() = True
<tmp>/s9.py:6: RuntimeWarning: coroutine 'inner' was never awaited
except RuntimeError as e: print('关闭后的循环再 run_until_complete ->', repr(e))
RuntimeWarning: Enable tracemalloc to get the object allocation traceback
一个 Lock 跨两次 asyncio.run(退出码 0):
第一次 asyncio.run -> got
第二次 asyncio.run 复用同一个 Lock -> RuntimeError('<asyncio.locks.Lock object at 0x105da6ba0 [locked]> is bound to a different event loop')循环外创建任务、循环关闭后再用、跨 asyncio.run 复用同步原语,各有各的 RuntimeError 文本。