#python #asynchronous #tcp #python-asyncio #httpx
Вопрос:
У меня около 130 асинхронных запросов GET, отправляемых с использованием httpx и asyncio в python, через прокси-сервер, который я сам создал на AWS.
В скрипте python я напечатал время непосредственно перед отправкой каждого запроса и вижу, что все они отправляются менее чем за 70 мс. Тем не менее, я рассчитал продолжительность запросов, получив текущее время сразу после этого, и некоторые запросы занимают до 30 секунд! Распределение кажется довольно ровным за это время, поэтому я получаю примерно 3-5 запросов каждую секунду в течение 30 секунд.
Я использовал tcpdump и wireshark, чтобы посмотреть на возвращающиеся пакеты, и кажется, что все данные приложения возвращаются в течение 4 секунд (включая tcp-рукопожатия), поэтому я не понимаю причину задержки в python.
Разрывы tcp происходят до 35 секунд спустя, так что, возможно, это может быть причиной задержки? Ожидает ли httpx закрытия соединения (FIN и ACK), прежде чем httpx.get() будет разблокирован и запрос можно будет прочитать?
Что я могу сделать, чтобы ускорить это?
Вот упрощенная версия моего кода:
import asyncio import datetime import httpx from utils import store_data, get_proxy_addr CLIENT = None async def get_and_store_thing_data(thing): t0 = datetime.now() res = await CLIENT.get('https://www.placetogetdata.com', params={'thing': thing}) t1 = datetime.now() # It's this line that shows the time is anywhere from 0-30 seconds for the # request to return print(f'time taken: {t1-t0}') data = res.json() store_data(data) return data def get_tasks(things): tasks = [] for thing in things: tasks = get_and_store_thing_data(thing) tasks.append(tasks) return tasks async def run_tasks(tasks): global CLIENT CLIENT = httpx.AsyncClient(proxies={'https://': proxy_addr}) try: await asyncio.wait(tasks) finally: await CLIENT.aclose() def run(): proxy_addr = get_proxy_addr() tasks = get_tasks asyncio.run(run_tasks(tasks, proxy_addr))
Комментарии:
1. Все эти запросы выполняются в одном цикле событий? Может ли быть так, что обработка всех предыдущих ответов занимает 30 секунд? Можете ли вы добавить какой-нибудь код
2. Отправляется ли каждый запрос в уникальный домен или все они отправляются в один и тот же домен? Если последнее, то есть большая вероятность, что сервер вас задушит.
3. @IainShelvington Пожалуйста, посмотрите пример кода, который я добавил. Все они выполняются с помощью одного asyncio.run()
4. @dirn Да, все переходят в один и тот же домен….однако они не регулируются, так как я создал 26 прокси-серверов на всех серверах AWS с помощью одного балансировщика сетевой нагрузки, и я каждый раз получаю все данные для всех запросов…. когда я не использую прокси, я получаю сообщение об ошибке от домена и забанен на 5 минут. Кроме того, я посмотрел на возвращаемые пакеты с помощью wireshark, и все данные приложения возвращаются через несколько секунд. Похоже, локально возникает задержка между возвращением пакетов и кодом python, разблокирующим ожидаемую сопрограмму httpx.get
5. @JonnyShanahan если вы удалите все, кроме запроса и печати времени, затраченного на вашу функцию, значительно ли сократится затраченное время? У меня есть предчувствие, что 130 звонков
store_data
займет 30 секунд