Асинхронные запросы
Когда запросов много, ждать каждый по очереди — расточительно. На помощь приходит асинхронность.
Асинхронный запрос — вызов, который не блокирует программу на время ожидания ответа: пока один запрос «висит» в сети, можно отправлять и обрабатывать другие.
Зачем это нужно
Запрос к LLM долгий — секунды. Если обрабатывать 100 текстов последовательно (отправил → дождался → следующий), общее время — сумма всех ожиданий. Асинхронно их можно запустить «внахлёст»: пока ждём ответ на первый, уже летят второй, третий и так далее. Время сокращается в разы.
Последовательно: [запрос1][запрос2][запрос3] — медленно
Параллельно: [запрос1]
[запрос2]
[запрос3] — быстро (внахлёст)
Как выглядит асинхронный клиент (Claude)
SDK даёт асинхронную версию клиента. Запросы запускают как корутины и ждут все сразу через asyncio.gather.
import asyncio
import anthropic
client = anthropic.AsyncAnthropic()
async def ask(text):
resp = await client.messages.create(
model="claude-opus-4-8",
max_tokens=256,
messages=[{"role": "user", "content": text}],
)
return "".join(b.text for b in resp.content if b.type == "text")
async def main():
questions = ["Столица Франции?", "Столица Японии?", "Столица Бразилии?"]
# Запускаем все три запроса одновременно
answers = await asyncio.gather(*(ask(q) for q in questions))
for q, a in zip(questions, answers):
print(q, "->", a)
asyncio.run(main())
Подводные камни
- Rate limits. Запустить 1000 запросов разом — верный способ получить шквал 429. Ограничивайте параллелизм (например, семафором на N одновременных запросов).
- Обработка ошибок. Часть запросов может упасть;
gatherпо умолчанию роняет всё на первой ошибке — продумайте, собирать ли ошибки или прерываться. - Не для всего. Для огромных нелатентных объёмов лучше batch-режим (раздел 5): он дешевле и со своими лимитами.
Async или потоки?
Цель — занять время ожидания сети полезной работой. В Python для этого есть асинхронные клиенты (как выше) и пулы потоков. Async обычно эффективнее для большого числа сетевых запросов: нет накладных расходов на потоки, всё крутится в одном цикле событий. Главное — не путать async с настоящей параллельностью вычислений: тяжёлый CPU-код от asyncio быстрее не станет, выигрыш только на ожидании ввода-вывода (а запрос к LLM — это как раз ожидание сети).
Семафор: ограничиваем одновременность
sem = asyncio.Semaphore(5) # не больше 5 запросов разом
async def ask_limited(text):
async with sem:
return await ask(text)
Итог
- Async позволяет отправлять много запросов «внахлёст» и резко сократить общее время.
- SDK дают асинхронные клиенты (
AsyncAnthropic/ async-методы OpenAI). - Ограничивайте параллелизм семафором, чтобы не словить 429; для массивов — batch.