Asyncio未并行执行任务问题求助(附aiohttp示例代码)
解决Asyncio + aiohttp任务未并行执行的问题
我先帮你补全没写完的代码片段(应该是session参数没写完),然后分析问题根源和解决方案:
你的代码(补全后)
import asyncio from aiohttp import ClientSession async def fetch(url, session, index): async with session.get(url) as response: print("Before " + str(index)) buffer = await response.read() print("After " + str(index)) async def run(r): url = "http://google.com" tasks = [] # Fetch all responses within one Client session, # keep connection alive for all requests. async with ClientSession() as session: for i in range(r): task = asyncio.ensure_future(fetch(url, session, i)) tasks.append(task) # 这里大概率缺少了并行等待任务的关键代码
问题根源
你遇到的核心问题是没有正确触发任务的并行调度:
- 如果你的代码里是在循环中逐个
await每个fetch调用,程序会等第一个请求完全结束后才发起第二个,自然是串行执行; - 如果只是创建了任务但没有用
asyncio.gather()统一等待所有任务,任务可能根本不会被执行,或者无法并行推进。
正确的并行实现
要让IO密集型的HTTP请求并行执行,你需要把所有任务收集后,用asyncio.gather()一次性等待所有任务完成,这样事件循环就能在一个请求等待响应时,自动切换到另一个请求执行。
修改后的完整代码:
import asyncio from aiohttp import ClientSession async def fetch(url, session, index): async with session.get(url) as response: print(f"Before {index}") buffer = await response.read() print(f"After {index}") async def run(r): url = "http://google.com" tasks = [] async with ClientSession() as session: for i in range(r): # Python 3.7+推荐用create_task替代ensure_future task = asyncio.create_task(fetch(url, session, i)) tasks.append(task) # 并行等待所有任务完成,这是实现并行的关键 await asyncio.gather(*tasks) if __name__ == "__main__": asyncio.run(run(3))
关键说明
asyncio.create_task()是把协程包装成可调度的任务,添加到事件循环中,但不会立即阻塞等待它完成;asyncio.gather(*tasks)会统一等待所有传入的任务,期间事件循环会自动在各个任务间切换,把HTTP请求的等待时间利用起来处理其他任务;- 注意:Asyncio是单线程模型,只适合并行处理IO密集型操作(比如HTTP请求),如果是CPU密集型任务,需要结合多进程使用。
运行这段代码,你会看到Before的打印几乎同时出现,过一会儿After的打印陆续输出,这就证明任务是并行执行的。
内容的提问来源于stack exchange,提问作者rajan sthapit
相关产品推荐
相关产品推荐

