Ответ
asyncio.gather() — это функция, которая позволяет запускать несколько асинхронных операций (корутин или Future) конкурентно и агрегировать их результаты.
Основная задача — выполнить группу независимых асинхронных задач параллельно, а не последовательно, и дождаться завершения всех из них. Это значительно сокращает общее время выполнения.
Ключевые особенности:
- Конкурентный запуск: Все переданные корутины начинают выполняться в цикле событий практически одновременно.
- Сбор результатов: Возвращает список результатов в том же порядке, в котором были переданы задачи.
- Ожидание завершения: Блокирует выполнение до тех пор, пока все задачи не будут выполнены.
Пример:
import asyncio
import time
async def task(name, delay):
print(f"Задача {name} началась, ждет {delay} сек.")
await asyncio.sleep(delay)
print(f"Задача {name} завершена.")
return f"Результат от {name}"
async def main():
start_time = time.time()
# Задачи будут выполняться параллельно
results = await asyncio.gather(
task("A", 2),
task("B", 1)
)
end_time = time.time()
print(f"Результаты: {results}") # ['Результат от A', 'Результат от B']
# Общее время ~2 секунды, а не 3 (2+1)
print(f"Общее время выполнения: {end_time - start_time:.2f} сек.")
asyncio.run(main())
Обработка исключений
Если в одной из задач возникает исключение, gather по умолчанию немедленно пробрасывает его, отменяя остальные задачи. Чтобы собрать все результаты, включая исключения, используется флаг return_exceptions=True.
Ответ 18+ 🔞
Смотри, вот тебе про asyncio.gather() без соплей и заумных терминов, на пальцах.
Представь, что у тебя есть куча дел, которые можно делать одновременно, пока ты ждёшь ответа от сервера, читаешь файлы или просто тупишь в ожидании. Так вот, gather — это твой личный надсмотрщик, который кричит этим задачам: «А ну, все нахуй, одновременно начинаем!» и потом терпеливо ждёт, пока каждая не отчитается.
Что он делает, по сути:
- Запускает всё сразу. Не как дурак — сделал одно, потом другое, потом третье. Нет, блядь, все задачи стартуют в одном событийном цикле и работают конкурентно.
- Ждёт всех до последнего. Пока последний ленивый уёбок не закончит своё дело,
gatherне отпустит тебя дальше по коду. - Аккуратно собирает результаты. И выдаёт тебе их в том же порядке, в котором ты задачи передал. Удобно, ёпта.
Вот смотри, как это выглядит в жизни:
import asyncio
import time
async def task(name, delay):
print(f"Задача {name} началась, ждет {delay} сек.")
await asyncio.sleep(delay)
print(f"Задача {name} завершена.")
return f"Результат от {name}"
async def main():
start_time = time.time()
# Сейчас магия начнётся. Обе задачи стартанут ОДНОВРЕМЕННО.
results = await asyncio.gather(
task("A", 2), # Эта будет спать 2 секунды
task("B", 1) # А эта всего 1
)
end_time = time.time()
print(f"Результаты: {results}") # ['Результат от A', 'Результат от B']
# И вот охуенный момент: общее время будет ~2 секунды, а не 3 (2+1)!
print(f"Общее время выполнения: {end_time - start_time:.2f} сек.")
asyncio.run(main())
А что с ошибками, спросишь?
А вот тут интересно. По умолчанию, если одна задача пойдёт по пизде и выбросит исключение, gather сразу же заорёт «ВСЁ, ПИЗДЕЦ!» и отменит все остальные. Но если ты не идиот и хочешь получить ВСЕ результаты — и успешные, и проваленные — то передай флаг return_exceptions=True. Тогда он соберёт всё в кучу: и нормальные ответы, и объекты исключений. Дальше уже сам разбирайся, где что. Хитрая жопа, но иногда очень нужная.