为何asyncio.gather()比for循环更快?两段异步代码性能差异解析
为什么第一段异步代码比第二段快这么多?
两段代码的核心差异在于协程的执行方式:并发 vs 串行,具体原因如下:
第一段代码:异步并发执行
async def main(urls): session = aiohttp.ClientSession() ret = await asyncio.gather(*[get(url, session) for url in urls]) # ...
[get(url, session) for url in urls]会一次性创建所有50个协程对象,此时协程仅处于就绪状态,并未开始执行。asyncio.gather()会把所有协程提交给事件循环,让它们同时发起网络请求:当某个协程因等待网络响应进入IO阻塞时,事件循环会立刻切换到另一个就绪的协程继续执行,充分利用等待的空闲时间。- 总耗时取决于耗时最长的单个请求,因此仅需1.5秒左右。
第二段代码:同步串行执行
async def main(urls): session = aiohttp.ClientSession() ret = [await get(url, session) for url in urls] # ...
- 这个列表推导式是逐个等待协程完成:先执行第一个
await get(url, session),必须等该请求完全拿到响应、协程结束后,才会创建并执行第二个协程,以此类推。 - 50个请求是依次完成的,总耗时是所有请求耗时的总和,因此需要8-10秒,完全没有发挥异步编程的并发优势。
简单来说,asyncio.gather()是异步编程中实现批量并发的标准方式,而逐个await则退化成了同步执行,这就是两者性能差距巨大的根本原因。
内容的提问来源于stack exchange,提问作者Paitor
相关产品推荐
相关产品推荐

