Ответ
Для конкурентного запуска нескольких корутин и сбора их результатов используется высокоуровневая функция asyncio.gather().
Она принимает на вход одну или несколько корутин, планирует их выполнение в цикле событий и возвращает Future, который завершается, когда все переданные корутины отработали. Результатом является список возвращаемых значений корутин в том же порядке, в котором они были переданы.
Ключевые особенности:
- Простота использования: Идеально подходит для сценария "запустить всё и дождаться всех".
- Сбор результатов: Автоматически собирает и упорядочивает результаты.
- Обработка ошибок: По умолчанию, если одна из корутин вызывает исключение,
gather()немедленно прерывается и пробрасывает это исключение. Поведение можно изменить, установив флагreturn_exceptions=True, тогда исключения будут возвращены в списке результатов наравне с успешными значениями.
Пример:
import asyncio
async def fetch_data(source: str, delay: int) -> str:
print(f"Начинаю загрузку из {source}...")
await asyncio.sleep(delay)
result = f"Данные из {source}"
print(f"Загрузка из {source} завершена.")
return result
async def main():
# Запускаем обе корутины конкурентно
results = await asyncio.gather(
fetch_data("API", 2),
fetch_data("DB", 1)
)
print(f"nВсе результаты: {results}")
# Вывод покажет, что DB завершит работу раньше,
# но gather дождется завершения API.
# >> Начинаю загрузку из API...
# >> Начинаю загрузку из DB...
# >> Загрузка из DB завершена.
# >> Загрузка из API завершена.
# >>
# >> Все результаты: ['Данные из API', 'Данные из DB']
asyncio.run(main())
В отличие от asyncio.create_task(), которая только планирует выполнение корутины и немедленно возвращает объект Task, asyncio.gather() представляет собой более удобный способ для одновременного ожидания группы задач.