Максимизировать количество параллельных запросов (aiohttp) - PullRequest
1 голос
/ 20 марта 2019

tl; dr : как максимально увеличить количество http-запросов, которые я могу отправлять параллельно?

Я получаю данные из нескольких URL-адресов с помощью библиотеки aiohttp.Я тестирую его производительность, и я заметил, что где-то в процессе есть узкое место, где одновременный запуск нескольких 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) Я вижу, что добавление большего количества URL для одновременного запуска помогает только до ~ 100 URL, а затем общее время начинает растипропорционально количеству URL-адресов (или, другими словами, время на один URL-адрес не уменьшается). Это говорит о том, что что-то не получается при попытке обработать их одновременно. Кроме того, с большим количеством URL-адресов в «одном пакете» я иногда получаю тайм-аут соединенияошибки.

enter image description here

  • Почему это происходит? Что именно ограничивает скорость здесь?
  • Как я могу проверить, каково максимальное число параллельных запросов, которое я могу отправить на данный компьютер? (Я имею в виду точное число - не приблизительно "методом проб и ошибок", как указано выше)
  • Что я могу сделать для увеличения количество запросов, обработанных за один раз?

Я запускаю это в Windows.

РЕДАКТИРОВАТЬ в ответ на комментарий:

Это те же данные с ограничением, установленным на None.Лишь небольшое улучшение в конце, и есть много ошибок тайм-аута соединения с одновременной отправкой 400 URL.В итоге я использовал limit = 200 для своих фактических данных.

enter image description here

1 Ответ

3 голосов
/ 20 марта 2019

По умолчанию aiohttp ограничивает количество одновременных подключений 100. Это достигается установкой по умолчанию limit в TCPConnector объекта , используемого ClientSession. Вы можете обойти это, создав и передав пользовательский соединитель сеансу:

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

Обратите внимание, что вы, вероятно, не хотите устанавливать слишком большое значение: емкость вашей сети, ЦП, ОЗУ и целевой сервер имеют свои собственные ограничения, и попытка установить огромное количество соединений может привести к увеличению отказов.

Оптимальное число, вероятно, можно найти только путем экспериментов на конкретной машине.


Unrelated:

Вам не нужно создавать задачи без причины . Большинство asyncio api принимают регулярные сопрограммы. Например, ваши последние строки кода могут быть изменены следующим образом:

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

Или даже просто asyncio.run(run(url_list)) ( doc ), если вы используете Python 3.7

...