Асинхронные HTTP-запросы в Python с httpx
Когда программа большую часть времени ждёт сеть, асинхронность даёт реальный выигрыш: пока один запрос ждёт ответа, цикл событий занимается остальными. В Python для HTTP это удобно делать через httpx — у него знакомый API и встроенная поддержка async.
Один клиент на много запросов
Главное правило — переиспользовать один AsyncClient, чтобы соединения держались в пуле, а не открывались заново на каждый запрос:
import asyncio
import httpx
async def fetch(client, url):
r = await client.get(url)
return url, r.status_code
async def main(urls):
async with httpx.AsyncClient(timeout=10) as client:
tasks = [fetch(client, u) for u in urls]
return await asyncio.gather(*tasks)
results = asyncio.run(main(["https://example.com"] * 50))
asyncio.gather запускает все корутины конкурентно и собирает результаты. Полсотни запросов выполнятся примерно за время самого медленного, а не за их сумму.
Таймауты и устойчивость
- Всегда задавайте timeout — без него зависший сервер заблокирует задачу навсегда.
- Для контроля нагрузки оборачивайте запросы в asyncio.Semaphore, чтобы не открыть тысячу соединений разом.
- gather(*tasks, return_exceptions=True) не уронит всю пачку из-за одной ошибки.
Этого набора достаточно, чтобы превратить медленный последовательный обход API в быстрый конкурентный, не уходя в ручное управление потоками.