Ответ
Модуль asyncio предоставляет инфраструктуру для написания однопоточного конкурентного кода с использованием корутин. Ключевые функции:
-
asyncio.run(coro): Высокоуровневая точка входа для запуска асинхронной программы. Автоматически создает и управляет циклом событий (event loop). -
asyncio.create_task(coro): Планирует асинхронную функцию для параллельного (конкурентного) выполнения в цикле событий. Немедленно возвращает объектTask, не дожидаясь завершения корутины. -
asyncio.gather(*aws): Запускает несколько асинхронных операций одновременно и возвращает список их результатов после того, как все они будут завершены. -
asyncio.sleep(delay): Неблокирующая пауза. Приостанавливает выполнение текущей корутины наdelayсекунд, позволяя циклу событий выполнять другие задачи. -
asyncio.wait_for(aw, timeout): Ожидает завершения асинхронной операции с указанным таймаутом. Если время истекло, вызывает исключениеasyncio.TimeoutError. -
asyncio.to_thread(func, *args): Асинхронно запускает блокирующую (синхронную) функцию в отдельном потоке, не блокируя основной цикл событий. Это основной способ интеграции legacy-кода.
Пример использования:
import asyncio
import time
async def fetch_data(source: str):
print(f"Начинаю загрузку из {source}...")
await asyncio.sleep(1) # Имитация I/O операции
print(f"Загрузка из {source} завершена.")
return {"source": source, "data": "..."}
async def main():
start_time = time.time()
# Запускаем обе задачи конкурентно
task1 = asyncio.create_task(fetch_data("API"))
task2 = asyncio.create_task(fetch_data("DB"))
# Ожидаем завершения обеих задач
results = await asyncio.gather(task1, task2)
print(f"Получены результаты: {results}")
end_time = time.time()
print(f"Все операции заняли {end_time - start_time:.2f} секунд.")
# Запускаем основную корутину
asyncio.run(main())
# Вывод покажет, что общее время выполнения ~1 секунда, а не 2. Ответ 18+ 🔞
Давай разберём эту асинхронную хрень, как есть. Ну, модуль asyncio, блядь, — это такая штука, которая позволяет твоему однопоточному коду делать вид, что он делает кучу дел одновременно. Не путай с многопоточностью, тут всё в одном потоке вертится, но по-хитрому.
Вот основные инструменты, без которых ты нихуя не сделаешь:
-
asyncio.run(coro): Это типа главная дверь в этот асинхронный бардак. Запускаешь свою главную корутину, а она уже внутри сама создаёт этот самый цикл событий, этот вечный двигатель, который всё и крутит. Просто вызвал — и поехали. -
asyncio.create_task(coro): А вот это, сука, ключевая вещь! Ты говоришь циклу: «Слушай, вот эту штуку (coro) мне нужно выполнить, но я не буду на неё тут же ждать, пусть себе работает на фоне». Функция сразу же возвращает тебе объектTask(задачу) и говорит «пошёл нахуй, делай что хочешь дальше». А задача уже тихонько себе планируется на выполнение. Без этого — никакой конкурентности, будет просто последовательный вызов. -
asyncio.gather(*aws): Ты накидал кучу задач черезcreate_task, а теперь хочешь подождать, пока они все дохуяриваются. Вотgatherкак раз для этого. Он запускает их всех и возвращает результаты, когда последняя ленивая жопа закончит. Удобно, ёпта. -
asyncio.sleep(delay): Это неtime.sleep, который всё заблокирует и уснёт! Это асинхронная поспать. Корутина говорит: «Я тут подожду секундочку, а ты, цикл событий, иди другие дела делай, не стой столбом». Через секунду она проснётся и продолжит. -
asyncio.wait_for(aw, timeout): Ждёшь чего-то, а оно тупит. Чтобы не ждать до второго пришествия, оборачиваешь вwait_forс таймаутом. Не успело — получиasyncio.TimeoutErrorв ебало и иди дальше. -
asyncio.to_thread(func, *args): О, это спасение, когда у тебя есть старый, кривой, блокирующий код, который никуда не годится для асинхронщины. Этой функцией ты вышвыриваешь эту тяжёлую синхронную работу в отдельный поток, чтобы она не забивала мозги твоему главному циклу. Интеграция легаси, так сказать.
Смотри, как это выглядит вживую:
import asyncio
import time
async def fetch_data(source: str):
print(f"Начинаю загрузку из {source}...")
await asyncio.sleep(1) # Прикидываемся, что ходим в сеть или в базу
print(f"Загрузка из {source} завершена.")
return {"source": source, "data": "..."}
async def main():
start_time = time.time()
# Создаём две задачи. Они начинают выполняться КОНКУРЕНТНО, ёба!
task1 = asyncio.create_task(fetch_data("API"))
task2 = asyncio.create_task(fetch_data("DB"))
# А теперь ждём, пока обе эти бандуры не отработают
results = await asyncio.gather(task1, task2)
print(f"Получены результаты: {results}")
end_time = time.time()
print(f"Все операции заняли {end_time - start_time:.2f} секунд.")
# Поехали!
asyncio.run(main())
# В выводе увидишь, что всё заняло около секунды, а не две, потому что спали они одновременно, хитрожопые.
Вот и вся магия. Главное — понять, что await это не блокировка, а точка, где корутина может сказать «стоп, я подожду, давай другую задачу». А create_task — это команда «начинай делать это параллельно». Всё остальное — детали, блядь.