Jupyter 中不能用 asyncio.run(),因其与内核已运行的事件循环冲突;应直接 await 协程,或使用 nest_asyncio 临时修复,避免修改标准库或在函数内使用 await。

不能直接用 asyncio.run(),因为 Jupyter 内核自己 already 在跑一个事件循环,Python 明确禁止嵌套启动。
为什么 asyncio.run() 一执行就报错
错误信息固定是:RuntimeError: asyncio.run() cannot be called from a running event loop。这不是你代码写错了,而是环境硬限制:IPython 启动时就调用了 loop.run_forever(),整个内核都依赖它;而 asyncio.run() 的行为是“新建 → 运行 → 关闭”,和已有循环根本冲突。
- 常见触发点:
asyncio.run(my_coro())、%run script.py(脚本里含asyncio.run)、某些旧版封装库(如部分httpxCLI 工具)内部硬编码了该调用 - 别手动试
asyncio.new_event_loop()+run_until_complete()—— IPython 的循环已深度绑定到内核通信,强行替换会导致输出丢失或单元格卡死
直接 await 协程(推荐首选)
Jupyter 单元格原生支持顶层 await(IPython ≥ 7.0,默认满足),无需额外包,也不用改协程定义。
- ✅ 正确写法:
result = await fetch_data() - ⚠️ 只能在单元格顶层用
await,不能在普通函数里写(否则报SyntaxError: 'await' outside async function) - 多个协程并行?用
await asyncio.gather(coro1(), coro2()),别一个个await - 如果协程依赖
asyncio.run()初始化的全局状态(比如老版本数据库驱动绑定了 loop),await可能行为异常,需查文档确认是否支持“已有 loop”模式
临时调试用 nest_asyncio
当你必须保留 asyncio.run()(比如复用外部脚本、测试第三方库),nest_asyncio 是唯一靠谱的修补方案。
立即学习“Python免费学习笔记(深入)”;
- 安装后只需两行:
!pip install nest_asyncio,然后import nest_asyncio; nest_asyncio.apply() - 它重写了
asyncio.get_event_loop(),让run_until_complete()和close()不再关闭已有循环 - 注意:
nest_asyncio是调试利器,但别带进生产服务——它绕过了 asyncio 的安全约束,可能掩盖资源泄漏或竞态问题
别碰 Windows 上改 asyncio.py 那套
网上有教程让你手动编辑 tornado/platform/asyncio.py 加 asyncio.set_event_loop_policy(),这属于过时且高危操作:
- 现代 Python(≥ 3.8)+ Jupyter(≥ 6.0)已默认适配 Windows Selector 策略 修改标准库文件极易引发版本混乱或后续升级失败
- 真正遇到 Windows 事件循环问题,优先检查是否混用了不同 Python 环境(比如 conda 和 pip 安装的包冲突)
最易被忽略的点:不是所有“异步函数”都能直接 await——比如某些库的同步 API 被误当成异步接口调用(典型如 playwright.sync_api 在 async 上下文中被调),这时报错不是循环冲突,而是 API 类型不匹配。


















