会。同步函数直接await会卡死事件循环,因time.sleep、requests.get等阻塞操作会阻塞事件循环线程;应使用loop.run_in_executor或asyncio.to_thread(3.9+)将其交由线程池执行。

同步函数直接await会卡死事件循环吗
会。Python异步函数里如果直接调用 time.sleep(5)、requests.get() 或任何未用 async 声明的阻塞操作,事件循环就停在那里不动了——其他协程全部等着,整个异步系统退化成单线程同步执行。
run_in_executor 的基本用法和参数选择
loop.run_in_executor() 是标准解法,它把同步函数扔进线程池(默认)或进程池执行,不占用事件循环线程。关键点在于:它返回一个 Future,必须 await 才能拿到结果。
常见写法:
import asyncio import time <p>def sync_work(): time.sleep(2) return "done"</p><p>async def main(): loop = asyncio.get_running_loop()</p><h1>默认使用 ThreadPoolExecutor</h1><pre class="brush:php;toolbar:false;">result = await loop.run_in_executor(None, sync_work) print(result)
参数说明:
-
None:用默认线程池(推荐,轻量) -
concurrent.futures.ThreadPoolExecutor(max_workers=4):自定义线程数,适合 I/O 密集型 -
concurrent.futures.ProcessPoolExecutor():CPU 密集型任务才考虑,但要注意对象序列化开销和全局解释器锁(GIL)实际影响
常见错误:忘记 await 或传参出错
典型翻车现场:
安全 Python 代码沙箱:在隔离的沙箱中执行任意 Python 代码,预装 requests、NumPy、pandas 库。返回 stdout、stderr。
- 写了
loop.run_in_executor(None, sync_work())—— 括号导致函数当场执行,不是传函数对象,事件循环照样卡住 - 写了
loop.run_in_executor(None, sync_work)但没await,结果是Future对象,后续逻辑拿不到返回值,还可能引发RuntimeWarning: coroutine 'xxx' was never awaited - 同步函数带参数时写成
run_in_executor(None, sync_work, arg1, arg2)是对的;但误写成run_in_executor(None, sync_work(arg1, arg2))就又同步执行了
比 run_in_executor 更轻量的替代方案
如果你只是想“不卡住”,且同步函数执行很快(毫秒级)、调用频繁,asyncio.to_thread()(Python 3.9+)更简洁:
result = await asyncio.to_thread(sync_work, arg1, arg2)
它内部就是封装了 run_in_executor + 线程池,但省去手动获取 loop 的步骤。注意:3.9 以下不支持,别硬套。
另外,不要为了“异步感”强行包装所有同步调用——比如本地文件读写小数据、简单计算,本身耗时远低于线程调度开销,加 run_in_executor 反而拖慢速度。
真正要盯住的是那些不可控的阻塞点:HTTP 请求、数据库查询、大文件处理、外部命令调用——这些才是 run_in_executor 应该出手的地方。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










