@Kirill-Gorelov
С ума с IT

Python, как сделать много запросов и получить ответ без ошибок?

Вопрос, как сделать много проверок за раз и получить ответ. То есть сделать аля сервис мониторинга страниц сайта.

Используем питон библиотеку aiohttp в многопоточности. На локалке выходит до 25 тысяч проверок за 2 минуты. У меня 8гб оперативки. Может на железе по мощнее будет и быстрее, не проверял пока, а может и код гавно. В перспективе таких проверок может вырасти до 300 тысяч...
Так же ознакомился с такой статьей https://pawelmhm.github.io/asyncio/python/aiohttp/..., но там только отправка, без обработки ответа ...

Вопрос:
1.Как можно увеличить либо число потоков, либо просто число проверок за раз?
2.Как правильно учесть вариант того, что страницы могут задерживать ответ, таймаут, но насколько грамотное это решение получиться?
3.Как правильно обрабатывать ответы, если будет приходить много данных за раз?

Ответ:
Как мне кажется, решение только одно использовать микросервисы.

Как это вижу я.
Приходит пул задач, условно 100 тысяч. Предварительно я их распихиваю по нескольким серверам, к примеру 5 шт. Значит на один сервер выходит 20 тысяч за раз. Все эти задачи сначала попадают в свои БД, на своих серверах, а потом их можно сливать в одну общую таблицу. Но можно и читать данные из разных серверов ... Но когда таких проверок вырастит еще больше, то нужно будет добавлять количество серверов и распределять все задачи между серверами....

Зачем мне это нужно? Да собственно говоря потренироваться, порешать для себя интересные задачки.... И потренировать разрабатывать микросервисы.

Может уже кто-то решал подобное или знает где такие задачи разбираются на примерах, буду благодарен.
  • Вопрос задан
  • 3613 просмотров
Решения вопроса 1
Во-первых, НИКОГДА не мешайте многопоточность с асинхронностью. Асинхронность придумали для того, чтобы не делать потоки.

Если я правильно понял, то Вы хотите сделать программу, которая проверяет работоспособность множества сайтов одновременно.
Смотрите:
Как можно увеличить либо число потоков, либо просто число проверок за раз?

Делайте несколько "воркеров" - то есть просто запускайте программу несколько раз. НО делать это на одном устройстве все равно скорее всего не будет никакого смысла, так как основная нагрузка будет на сеть, а не на процессор.

Предварительно я их распихиваю по нескольким серверам, к примеру 5 шт. Значит на один сервер выходит 20 тысяч за раз. Все эти задачи сначала попадают в свои БД, на своих серверах, а потом их можно сливать в одну общую таблицу. Но можно и читать данные из разных серверов ...

Вот именно так. Но базу данных можно делать одну на все сервера (sqlite не подойдет, mysql или postgreesql будут не плохим вариантом). Вы делаете основной сервер, где будет БД и 1 воркер и множество доп. серверов с 1 воркером на каждом, которые подключаются к БД на основном.

Дальше стоит понять, чем асинхронный запрос отличается от синхронного.
Запрос
6102683738193554639408.png
(максимально упрощенно, обычно все сложнее).
1. Синхронный: все время, отмеченное красным программа не работает, Ваша ОС приостанавливает ее выполнение. Получается, что программа одновременно может выполнять лишь один запрос, при этом большую часть времени она ничего не делает.
2. Асинхронный: ОС сразу возвращает ответ, типа "будет сделано" и программа может работать дальше. Но вам ведь нужен конкретный ответ, поэтому asyncio пока ждет ответа от ОС (которая ждет ответа от сервера), может выполнять другие задачи (например, начинать другие запросы). Теперь ваша программа может делать несколько запросов одновременно, их количество зависит уже от ОС и сети.

Как правильно учесть вариант того, что страницы могут задерживать ответ, таймаут, но насколько грамотное это решение получиться?

ОС будет сама отслеживать таймауты для каждого запроса отдельно. Таймаут можно указать руками при создании запроса, если этого не сделать, то он будет равен 5 минут (что для синхронного запроса ооочень много, но для асинхронного сойдет). Про таймаут можно почитать в документации.

Про задачи в asyncio. Чтобы выполнить несколько функций (псево)параллельно используется функция asyncio.gather():
async def make_request(address):
    ...
    return address, response  # чтобы потом можно было понять, на что это ответ

async def main():
    urls = [...]
    reqs = []
    for url in urls:
        reqs.append(make_request(url))  # Обратите внимание на отсутствие await, нам не нужно ждать завершения сейчас

    results = await asyncio.gather(reqs)  # gather объединяет несколько корутин в одну, теперь мы ждем, пока выполнятся все запросы
    # теперь results - list[tuple[<address>, <response>]]
    for url, result in results:
        print(...)  # print можно делать и в обработчике, тут уже зависит от того, что вы хотите сделать с ответом

Есть и другие способы запуска задач (ensure_future и create_task, возможно они вам больше подойдут).

Как правильно обрабатывать ответы, если будет приходить много данных за раз?

Каждый ответ обрабатывайте отдельно. Прямо сразу после запроса (в примере в функции make_request). Вот пример из документации.

Когда пишете код с aiohttp не забывайте, что async with session.get(...) as resp: и есть запрос. async with по сути внутри себя содержит await, поэтому пока выполняется такой код может выполниться еще несколько параллельных задач.

Еще отлаживать асинхронный код довольно сложно, поэтому используйте логирование (можно начать с обычных print-ов, только не print("xx") и print("yy"), а print(f"Starting request to {url}...") и print(f"Got response from {url}...") - иначе вы не сможете понять, какой сайт долго отвечает, сколько по времени выполняется запрос к 1 сайту (тут поможет logging и метки времени) и на каком количестве запросов программа виснет).
Ответ написан
Пригласить эксперта
Ответы на вопрос 1
@C0COK
не совсем понял что вы хотите именно добиться, но что мешает создать асинхронную многопоточность с try except, указанием timeout и verify=False ? каждый поток работает сам по себе, не ждет предыдущего, а timeout отвечает за максимальное ожидание ответа от сайта.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы