最大化并行请求数 (aiohttp)

pie*_*eca 4 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()
Run Code Online (Sandbox Code Playgroud)

以url_list不同的长度运行这个(针对https://httpbin.org/delay/2 的测试)我看到添加更多的 url 一次运行最多只能帮助大约 100 个 url,然后总时间开始与数量成正比增长urls(或者换句话说,每个 url 的时间不会减少)。这表明在尝试立即处理这些时会出现问题。此外,在“一批”中有更多网址时,我偶尔会收到连接超时错误。

在此处输入图片说明

  • 为什么会发生?究竟是什么限制了这里的速度?
  • 如何检查在给定计算机上可以发送的最大并行请求数是多少?(我的意思是一个确切的数字 - 不是如上所述的“反复试验”)
  • 我可以做些什么来增加一次处理的请求数量?

我在 Windows 上运行这个。

编辑以回应评论:

这是限制设置为 的相同数据None。最后只有轻微的改进,并且一次发送了 400 个 url 的连接超时错误很多。我最终使用limit = 200了我的实际数据。

在此处输入图片说明

Mik*_*mov 7

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

connector = aiohttp.TCPConnector(limit=None)
async with aiohttp.ClientSession(connector=connector) as session:
    # ...
Run Code Online (Sandbox Code Playgroud)

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

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


无关:

您不必无故创建任务。大多数 asyncio api 接受常规协程。例如,您的最后几行代码可以这样修改:

loop = asyncio.get_event_loop()
loop.run_until_complete(run(url_list))
Run Code Online (Sandbox Code Playgroud)

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