Python 同步代码与异步代码的协作

发布时间 - 2026-01-29 00:00:00    点击率:
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 秒,其他任务全部挂起。

必须替换成异步等价物:

  • await asyncio.sleep(5) 替代 time.sleep(5)
  • aiohttp.ClientSessionhttpx.AsyncClient 替代 requests
  • 数据库操作必须用异步驱动(如 asyncpgaiomysqlmotor),不能用 psycopg2pymysql

如果实在绕不开同步库(比如某 SDK 只提供 sync 接口),可用 loop.run_in_executor() 把它扔进线程池执行,避免阻塞事件循环。

从同步函数安全调用异步函数的三种场景

实际项目中,常有老代码是同步的,但新模块是异步的,比如 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 的 Dep

    ends
    ),直接 await fetch_data() —— 框架已确保你在 async 上下文里

async/await 与 threading 的混合使用容易引发状态混乱

有人想“既用 async 提高 I/O 并发,又用 threading 做 CPU 密集计算”,这没问题;但要注意:协程不绑定线程,asyncio 默认只在一个线程里调度所有协程。如果你在 run_in_executor 里修改了某个全局变量或类实例属性,而主线程的协程也同时读写它,就会出现竞态。

关键约束:

  • asyncio 的原生对象(如 asyncio.Queueasyncio.Lock)只能在协程中 await,不能在线程里用
  • 线程间共享数据,仍得用 threading.Lockqueue.Queue 等传统同步原语
  • 避免在 executor 中操作 event loop 相关对象(如 loop.call_soon_threadsafe 是例外,但应尽量少用)

最稳妥的做法是:I/O 交给 async,CPU 密集交给 concurrent.futures.ProcessPoolExecutor(而非 ThreadPoolExecutor),彻底隔离内存空间。


# mysql  # python  # go  # 工具  # session  # ai  # 路由  # 解决方法  # django  # flask  # fastapi  # httpx  # ipython  # try  # 全局变量  # 循环  # 接口  # Event  # 线程  # 多线程  # 主线程  # 并发  # 对象  # 事件  # 异步  # jupyter  # 数据库  # https  # 你在  # 已有  # 能在  # 会报  # 这是  # 就会  # 运行环境  # 把它  # 三种  # 只在 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何制作新型网站程序文件,新型止水鱼鳞网要拆除吗?  香港服务器部署网站为何提示未备案?  jQuery中的100个技巧汇总  JavaScript如何操作视频_媒体API怎么控制播放  厦门模型网站设计制作公司,厦门航空飞机模型掉色怎么办?  家族网站制作贴纸教程视频,用豆子做粘帖画怎么制作?  QQ浏览器网页版登录入口 个人中心在线进入  齐河建站公司:营销型网站建设与SEO优化双核驱动策略  为什么要用作用域操作符_php中访问类常量与静态属性的优势【解答】  如何用好域名打造高点击率的自主建站?  手机网站制作与建设方案,手机网站如何建设?  企业网站制作这些问题要关注  Laravel怎么处理异常_Laravel自定义异常处理与错误页面教程  详解一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)  INTERNET浏览器怎样恢复关闭标签页_INTERNET浏览器标签恢复快捷键与方法【指南】  如何快速辨别茅台真假?关键步骤解析  网站图片在线制作软件,怎么在图片上做链接?  Laravel的契約(Contracts)是什么_深入理解Laravel Contracts与依赖倒置  香港服务器网站测试全流程:性能评估、SEO加载与移动适配优化  Laravel如何安装使用Debugbar工具栏_Laravel性能调试与SQL监控插件【步骤】  WordPress 子目录安装中正确处理脚本路径的完整指南  Zeus浏览器网页版官网入口 宙斯浏览器官网在线通道  ,交易猫的商品怎么发布到网站上去?  中国移动官方网站首页入口 中国移动官网网页登录  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  Laravel如何处理跨站请求伪造(CSRF)保护_Laravel表单安全机制与令牌校验  Angular 表单中正确绑定输入值以确保提交与验证正常工作  Laravel的HTTP客户端怎么用_Laravel HTTP Client发起API请求教程  Laravel任务队列怎么用_Laravel Queues异步处理任务提升应用性能  装修招标网站设计制作流程,装修招标流程?  如何在腾讯云服务器快速搭建个人网站?  Laravel如何使用集合(Collections)进行数据处理_Laravel Collection常用方法与技巧  Laravel如何处理文件上传_Laravel Storage门面实现文件存储与管理  rsync同步时出现rsync: failed to set times on “xxxx”: Operation not permitted  香港服务器建站指南:免备案优势与SEO优化技巧全解析  javascript基于原型链的继承及call和apply函数用法分析  Laravel如何生成URL和重定向?(路由助手函数)  如何用PHP工具快速搭建高效网站?  Python文件异常处理策略_健壮性说明【指导】  Laravel如何处理文件下载请求?(Response示例)  怎么制作一个起泡网,水泡粪全漏粪育肥舍冬季氨气超过25ppm,可以有哪些措施降低舍内氨气水平?  BootStrap整体框架之基础布局组件  Python结构化数据采集_字段抽取解析【教程】  大连网站制作费用,大连新青年网站,五年四班里的视频怎样下载啊?  Python图片处理进阶教程_Pillow滤镜与图像增强  矢量图网站制作软件,用千图网的一张矢量图做公司app首页,该网站并未说明版权等问题,这样做算不算侵权?应该如何解决?  Python文件操作最佳实践_稳定性说明【指导】  如何在宝塔面板中创建新站点?  悟空识字如何进行跟读录音_悟空识字开启麦克风权限与录音  php中::能调用final静态方法吗_final修饰静态方法调用规则【解答】