为何使用asyncio.to_thread时需要执行两次await?
问题分析与解决
你的代码核心问题有两个,直接给你拆解清楚:
1. 变量名拼写错误引发异常
循环里你写的是asyncio.to_thread(do_lookup, keyword, index),但当前循环变量是kw,keyword根本没定义,运行时会直接抛出NameError。这大概率是你误以为await result返回协程的原因——其实是报错打断了正常流程,让你产生了误解。
2. 对to_thread和as_completed的逻辑误解
asyncio.to_thread本身返回的就是可等待的协程对象,不需要额外await一次再添加到集合里。asyncio.as_completed接收这些协程后,返回的迭代器每次产出的是已完成的Future对象,await这个Future就能直接拿到do_lookup的返回值,不存在“返回另一个协程”的情况。
修正后的代码
import asyncio async def search(keyword_list): coroutines = set() for index, kw in enumerate(keyword_list): # 修复变量未定义问题:把keyword改成kw coroutines.add(asyncio.to_thread(do_lookup, kw, index)) for result in asyncio.as_completed(coroutines): # await result直接获取do_lookup的返回值 outcome, idx = await result print(f"处理结果:关键词{outcome},索引{idx}") async def do_lookup(keyword, index): # 模拟阻塞IO操作(实际替换为真实的阻塞逻辑即可) await asyncio.sleep(1) print(f'running...{keyword} {index}') return keyword, index if __name__ == '__main__': asyncio.run(search([1, 2, 3, 4]))
补充说明
asyncio.to_thread的作用就是把阻塞函数放到单独线程运行,返回的协程对象可直接被事件循环调度,无需手动处理线程细节。- 如果不需要按任务完成顺序处理结果,也可以用
await asyncio.gather(*coroutines)一次性获取所有结果,返回的结果会和协程添加顺序一致。
内容的提问来源于stack exchange,提问作者Will Gordon
相关产品推荐
相关产品推荐

