async函数中可直接调用同步函数但会阻塞事件循环,耗时操作须用loop.run_in_executor;同步代码中需用asyncio.run()启动事件循环才能await异步函数;混用时须严格管理loop生命周期,禁用time.sleep等阻塞调用。

async 函数里怎么调用普通同步函数
直接调用没问题,但会阻塞事件循环——这是最常被忽略的性能雷区。
比如在 async def handle_request() 里写 json.loads(data) 或 os.path.exists(path),语法上完全合法,但一旦同步函数耗时稍长(比如读文件、解析大 JSON、正则匹配超长文本),整个 asyncio 任务就卡住,其他协程全得等它。
- 推荐做法:把真正耗时的同步操作包进
loop.run_in_executor(),交给线程池执行 - 简单场景(如小数据转换)可保留直接调用,但心里得有数:它不“异步”,只是“没报错”
- 别用
asyncio.to_thread()(Python 3.9+)替代线程池——它底层也是run_in_executor,但封装略多一层,调试时堆栈更难读
同步代码里怎么安全 await 异步函数
不能直接 await,会报 RuntimeError: no running event loop。这不是语法错误,是运行时环境缺失。
常见于命令行脚本、测试 setup、或老项目中临时加个异步调用——比如想在普通函数里调用 httpx.AsyncClient().get()。
立即学习“Python免费学习笔记(深入)”;
Modoer 是一款以本地分享,多功能的点评网站管理系统。采用 PHP+MYSQL 开发设计,开放全部源代码。因具有非凡的访问速度和卓越的负载能力而深受国内外朋友的喜爱,不局限于商铺类点评,真正实现了多类型的点评,可以让您的网站点评任何事与物,同时增加产品模块,也更好的网站产品在网站上展示。Modoer点评系统 2.5 Build 20110710更新列表1.同步 旗舰版系统框架2.增加 限制图片
- 如果确定只在顶层跑一次,用
asyncio.run(main())包一层最干净 - 已在运行的线程里(比如 Flask 的 request handler),别自己
asyncio.new_event_loop()—— 多个 loop 容易冲突,改用asyncio.get_event_loop().run_until_complete(...)(前提是 loop 确实已启动) - 别在同步函数里反复创建/关闭 loop,尤其不能在循环体内调用
asyncio.run()—— 开销大,还可能抛RuntimeError: asyncio.run() cannot be called from a running event loop
混合项目里 event loop 生命周期怎么管
混用 sync/async 最容易崩的不是语法,而是 loop 启停时机不对——比如子线程里没显式 set loop,或者主线程 exit 前没 clean 掉 pending task。
典型现象:Task was destroyed but it is pending! 或程序退出时卡住几秒才结束。
- 避免在非主线程里依赖
asyncio.get_event_loop(),改用asyncio.new_event_loop()+set_event_loop()显式管理 - 用
asyncio.run()启动的 loop,退出时自动 cleanup;但手动loop.run_forever()的,必须配对调用loop.close() - 第三方库(如 aiomysql、aiofiles)初始化时可能隐式访问 loop,确保它们的 setup 发生在 loop 创建之后、start 之前
哪些同步操作绝对不能扔进 async 函数里
不是所有“看起来快”的同步代码都适合直接嵌入协程——关键看它是否可能触发系统调用或不可控延迟。
比如 time.sleep(1) 表面只停 1 秒,但它会彻底冻结当前协程;而 asyncio.sleep(1) 才让出控制权给其他任务。
- 禁用:
time.sleep()、input()、阻塞式 socket 操作(如socket.connect())、subprocess.call() - 慎用:
json.loads()(小数据 OK,GB 级 JSON 会卡住)、re.sub()(回溯爆炸时 CPU 跑满)、sqlite3.connect()(磁盘 I/O,应换aiosqlite) - 检查方法:用
strace -e trace=epoll_wait,read,write,fsync python your_script.py看有没有意外阻塞系统调用
async 和 sync 协作不是靠“能跑通”,而是靠清楚每一行代码在哪条线程、哪个 loop 上执行。漏掉一个 run_in_executor,或错判一次 sleep 类型,就可能让整个服务响应时间从毫秒跳到秒级。









