asyncio.run() 不能在已运行的事件循环中调用,应在顶层脚本中使用;在已有 loop 环境(如 Jupyter、FastAPI)中改用 create_task 或 run_until_complete;同步阻塞操作须替换为异步等价物或通过 run_in_executor 调用。

asyncio.run() 不能在已运行的事件循环中调用
这是最常见的协作崩溃点:你在 Jupyter、Django shell 或 FastAPI 的异步路由里,直接调用 asyncio.run(main()),会报 RuntimeError: asyncio.run() cannot be called from a running event loop。因为这些环境本身已启动了事件循环,asyncio.run() 试图再启一个,冲突了。
解决方法不是“换库”,而是判断上下文:
- 在顶层脚本(无现成 loop)中,用
asyncio.run()是安全且推荐的 - 在已有 loop 的环境里(如
ipython),改用asyncio.create_task()或asyncio.ensure_future()提交协程 - 需要从同步函数“等”一个异步结果时,用
asyncio.get_event_loop().run_until_complete(coro)(Python 3.7+ 兼容,但注意 loop 可能未启动)
同步阻塞调用(如 time.sleep、requests.get)会卡死整个异步流程
异步代码不是“多线程”,它依赖协程让出控制权。一旦混入同步阻塞操作,比如 time.sleep(5) 或 requests.get("https://httpbin.org/delay/5"),当前协程就真睡了 5 秒,其他任务全部挂起。
必须替换成异步等价物:
立即学习“Python免费学习笔记(深入)”;
- 用
await asyncio.sleep(5)替代time.sleep(5) - 用
aiohttp.ClientSession或httpx.AsyncClient替代requests - 数据库操作必须用异步驱动(如
asyncpg、aiomysql、motor),不能用psycopg2或pymysql
如果实在绕不开同步库(比如某 SDK 只提供 sync 接口),可用 loop.run_in_executor() 把它扔进线程池执行,避免阻塞事件循环。
Modoer 是一款以本地分享,多功能的点评网站管理系统。采用 PHP+MYSQL 开发设计,开放全部源代码。因具有非凡的访问速度和卓越的负载能力而深受国内外朋友的喜爱,不局限于商铺类点评,真正实现了多类型的点评,可以让您的网站点评任何事与物,同时增加产品模块,也更好的网站产品在网站上展示。Modoer点评系统 2.5 Build 20110710更新列表1.同步 旗舰版系统框架2.增加 限制图片
从同步函数安全调用异步函数的三种场景
实际项目中,常有老代码是同步的,但新模块是异步的,比如 Flask 路由要调用一个 async def fetch_data()。不能直接 fetch_data()(返回 coroutine 对象),也不能 await fetch_data()(语法错误,不在 async 函数里)。
对应策略取决于运行环境:
- 若确定当前无 event loop(如普通脚本),用
asyncio.run(fetch_data()) - 若不确定是否有 loop(如通用工具函数),先检查:
try: loop = asyncio.get_running_loop() except RuntimeError: loop = None,再按需选择loop.create_task()或asyncio.run() - 若在已知有 loop 的框架中(如 FastAPI 的
Depends),直接await fetch_data()—— 框架已确保你在 async 上下文里
async/await 与 threading 的混合使用容易引发状态混乱
有人想“既用 async 提高 I/O 并发,又用 threading 做 CPU 密集计算”,这没问题;但要注意:协程不绑定线程,asyncio 默认只在一个线程里调度所有协程。如果你在 run_in_executor 里修改了某个全局变量或类实例属性,而主线程的协程也同时读写它,就会出现竞态。
关键约束:
-
asyncio的原生对象(如asyncio.Queue、asyncio.Lock)只能在协程中 await,不能在线程里用 - 线程间共享数据,仍得用
threading.Lock、queue.Queue等传统同步原语 - 避免在 executor 中操作 event loop 相关对象(如
loop.call_soon_threadsafe是例外,但应尽量少用)
最稳妥的做法是:I/O 交给 async,CPU 密集交给 concurrent.futures.ProcessPoolExecutor(而非 ThreadPoolExecutor),彻底隔离内存空间。









