API допускает максимум 100 запросов в минуту, и мне нужно получать данные для десятков тысяч элементов.
Вот упрощенная версия моего текущего подхода с использованием asyncio и aiohttp:
Код: Выделить всё
import asyncio
import aiohttp
async def fetch(session, url):
async with session.get(url) as resp:
return await resp.json()
async def main(urls):
async with aiohttp.ClientSession() as session:
tasks = [fetch(session, url) for url in urls]
results = await asyncio.gather(*tasks)
return results
urls = [f"https://api.example.com/items/{i}" for i in range(10000)]
data = asyncio.run(main(urls))
Я пробовал ввести семафоры и интервалы ожидания:
Код: Выделить всё
semaphore = asyncio.Semaphore(10)
async def fetch_limited(session, url):
async with semaphore:
async with session.get(url) as resp:
if resp.status == 429:
await asyncio.sleep(60)
return await fetch_limited(session, url)
return await resp.json()
Это неэффективно — спящие режимы блокируют все задачи, а не только те, которые ограничены по скорости.
У меня все еще иногда возникают всплески 429, вероятно, из-за планирования параллелизма.
Повторные попытки непоследовательны и могут привести к зависанию некоторых задач.
Вопрос:
Каков наиболее эффективный и Pythonic способ:
Асинхронно распараллелить большое количество вызовов API
Соблюдать строгие ограничения скорости (например, 100 запросов в минуту)
Четко обрабатывать повторы и экспоненциальную отсрочку
Избегать блокировки цикла событий при ограничении скорости
Будет использоваться такие библиотеки, как aiolimiter, tenacity или архитектура asyncio.Queue, подходят лучше?
Я ищу надежный шаблон проектирования или пример, который изящно масштабируется, не нарушая ограничений скорости.
Подробнее здесь: https://stackoverflow.com/questions/798 ... -in-python
Мобильная версия