asyncio.to_thread(...)
会把你传入的同步函数 丢到另一个线程中执行,这个线程来自一个默认的线程池(默认是 ThreadPoolExecutor
)。
✅ 更具体一点的说法是:
- 它不会阻塞主线程(也就是事件循环);
- 你可以用
await
异步地等这个函数跑完; - 这个执行过程 实际上是“在后台线程中同步执行”,只是你用异步的方式接了个壳。
✅ 举个比喻(人话):
你现在是个老板(主协程),你在处理一堆任务。
这时有个特别费力的体力活,比如:
📦 搬仓库里 10 万箱货(纯 CPU / 同步阻塞函数)
你不想自己干(不想阻塞自己),就把这个活:
✅
asyncio.to_thread(...)
➜ 派个临时工(线程)去干
你自己继续办公(事件循环继续跑),等这个活干完后,临时工回来告诉你:
“老板,我搬完了!”——然后你
await
收到结果。
✅ 代码上的行为:
假设你写:
result = await asyncio.to_thread(sync_func, *args)
等价于(简化理解):
from concurrent.futures import ThreadPoolExecutor
loop = asyncio.get_event_loop()
executor = ThreadPoolExecutor()
future = loop.run_in_executor(executor, sync_func, *args)
result = await future
也就是说:确实是在一个“真正的线程”中跑的!
✅ 补充:它不是每次都开新线程!
虽然你可以把它理解为“丢给一个线程”执行,但实际上:
- 它会复用默认的
ThreadPoolExecutor
; - 所以不会每次都“新建一个线程”,而是把任务交给线程池中的线程去跑(这更高效);
- 默认线程池大小是
min(32, os.cpu_count() + 4)
(最多 32 个线程); - 当然你可以自己设置自定义线程池(高级用法);
✅ 小结一句话:
✅
asyncio.to_thread
就是把你写的同步代码(例如磁盘读写、大计算)丢到另一个线程里异步执行,对主协程非常友好(不会卡 UI、不阻塞事件循环)。