最大化并行请求数(aiohttp)

时间:2019-03-20 11:32:05

标签: python asynchronous request python-asyncio aiohttp

tl; dr :如何最大化可并行发送的http请求的数量?

我正在使用aiohttp库从多个URL中获取数据。我正在测试其性能,并且发现该过程中的某个地方存在瓶颈,即一次运行更多url并没有帮助。

我正在使用以下代码:

import asyncio
import aiohttp

async def fetch(url, session):
    headers = {'User-Agent': 'Mozilla/5.0 (Windows NT 6.3; Win64; x64; rv:64.0) Gecko/20100101 Firefox/64.0'}
    try:
        async with session.get(
            url, headers=headers, 
            ssl = False, 
            timeout = aiohttp.ClientTimeout(
                total=None, 
                sock_connect = 10, 
                sock_read = 10
            )
        ) as response:
            content = await response.read()
            return (url, 'OK', content)
    except Exception as e:
        print(e)
        return (url, 'ERROR', str(e))

async def run(url_list):
    tasks = []
    async with aiohttp.ClientSession() as session:
        for url in url_list:
            task = asyncio.ensure_future(fetch(url, session))
            tasks.append(task)
        responses = asyncio.gather(*tasks)
        await responses
    return responses

loop = asyncio.get_event_loop()
asyncio.set_event_loop(loop)
task = asyncio.ensure_future(run(url_list))
loop.run_until_complete(task)
result = task.result().result()

以不同长度的url_list运行此文件(针对 https://httpbin.org/delay/2 进行测试),我发现一次添加更多要运行的网址最多只能提供约100个网址,然后总时间开始与网址数量成正比增长(换句话说,每个网址的时间不会减少)。这表明尝试立即处理这些操作时某些操作失败。此外,“一批”中有更多url,我偶尔会收到连接超时错误。

enter image description here

  • 为什么会这样?到底什么限制了速度
  • 如何检查我可以在给定计算机上发送的并行请求的最大数量是多少? (我的意思是确切的数字-并非如上所述的“反复试验”得出的数字)
  • 我该如何增加一次处理的请求数?

我在Windows上运行。

编辑以回复评论:

这是相同的数据,其限制设置为None。最后仅稍有改进,一次发送400个URL时有许多连接超时错误。我最终在我的实际数据上使用了limit = 200

enter image description here

1 个答案:

答案 0 :(得分:3)

默认情况下,aiohttp将同时连接的数量限制为100。它可以通过将limit使用的默认TCPConnector设置为ClientSession object来实现。您可以通过创建自定义连接器并将其传递到会话来绕过它:

connector = aiohttp.TCPConnector(limit=None)
async with aiohttp.ClientSession(connector=connector) as session:
    # ...

但是请注意,您可能不想将此数字设置得太高:您的网络容量,CPU,RAM和目标服务器有其自身的限制,并尝试进行大量连接会导致故障增加。

最佳数量可能只能通过在混凝土机器上进行实验才能找到。


无关:

没有reason,您不必创建任务。大多数异步api接受常规协程。例如,您的最后几行代码可以通过以下方式更改:

loop = asyncio.get_event_loop()
loop.run_until_complete(run(url_list))

如果您使用的是Python 3.7,甚至只是asyncio.run(run(url_list))doc