为啥 aiohttp 比 gevent 慢得多?

Posted

技术标签:

【中文标题】为啥 aiohttp 比 gevent 慢得多?【英文标题】:Why is aiohttp horribly slower than gevent?为什么 aiohttp 比 gevent 慢得多? 【发布时间】:2018-10-08 07:11:33 【问题描述】:

免责声明:我是 aiohttp 的初学者

我正在尝试使用 aiohttp 来异步处理 get 请求,但结果证明它比池版本的 gevent 慢得多。

GEVENT 版本

import gevent
from gevent import monkey
monkey.patch_all()
from gevent.pool import Pool

import requests
import time

def pooling_task(url):
    requests.get(url)


def pooling_main():
    start = time.time()
    pool = Pool(10)
    urls = [
        "http://google.com",
        "http://yahoo.com",
        "http://linkedin.com",
        "http://shutterfly.com",
        "http://mypublisher.com",
        "http://facebook.com"
    ]
    for url in urls:
        pool.apply_async(pooling_task, args=(url,))

    pool.join()
    end = time.time()
    print("POOL TIME ".format(end-start))

if __name__ == '__main__':
    print("POOLING VERSION")
    pooling_main()

输出 - 池时间 6.299163818359375

以下是aiohttp版本

import aiohttp
import asyncio
import time
import uvloop

asyncio.set_event_loop_policy(uvloop.EventLoopPolicy())

async def fetch(session, url):
    async with session.get(url) as response:
        return await response.text()


async def main():
    urls = [
        "http://google.com",
        "http://yahoo.com",
        "http://linkedin.com",
        "http://shutterfly.com",
        "http://mypublisher.com",
        "http://facebook.com"]

    async with aiohttp.ClientSession() as session:
        for url in urls:
            await fetch(session, url)

if __name__ == "__main__":
    start = time.time()
    loop = asyncio.get_event_loop()
    loop.run_until_complete(main())
    end = time.time()
    print("Time taken ".format(end - start))

输出 - 耗时 15.399710178375244

我真的不明白为什么 aiohttp 这么慢。 至于gevent版本requests.get仍然是阻塞调用,但不是aiohttp。

我预计 aiohttp 版本会更快。

【问题讨论】:

【参考方案1】:
for url in urls:
    await fetch(session, url)

await 这里的意思是你在上一个完成之前不会开始下载下一个 url。要使所有下载同时进行,您应该使用 asyncio.gather 之类的内容。

像这样修改你的代码:

async with aiohttp.ClientSession() as session:
    await asyncio.gather(*[
        fetch(session, url)
        for url
        in urls
    ])

你会看到巨大的加速。

【讨论】:

谢谢,这个实现有效。但是 await fetch(session,url) 不会是一个阻塞调用,所以事件循环将从循环中获取下一个元素并开始获取下一个? 哦,我是多么愚蠢。当在 for 循环中时,eventloop 已经注意到 else 要运行。但是在收集的情况下,它还有其他协程要通过(由 fetch 生成的协程)

以上是关于为啥 aiohttp 比 gevent 慢得多?的主要内容,如果未能解决你的问题,请参考以下文章

为啥 NSURLSession dataTaskWithURL 比 NSData dataWithContentsOfURL 慢得多?

为啥 BufferedReader read() 比 readLine() 慢得多?

NSMutableDictionary 比 Java Map 慢得多……为啥?

为啥 TensorFlow matmul() 比 NumPy multiply() 慢得多?

为啥 renderInContext 比绘制到屏幕慢得多?

为啥 Hadoop SequenceFile 写入比读取慢得多?