gather:
results = await asyncio.gather(fetch(a), fetch(b), fetch(c))
Результаты — в порядке аргументов. Если fetch(b) упал, await gather бросит это исключение, но fetch(a) и fetch(c) не отменяются и продолжают работать в фоне; их ошибки могут потеряться («Task exception was never retrieved»).
С return_exceptions=True gather не бросает, а кладёт исключения в список результатов — удобно, когда нужно собрать всё, что получилось.
TaskGroup (Python 3.11):
async with asyncio.TaskGroup() as tg:
ta = tg.create_task(fetch(a))
tb = tg.create_task(fetch(b))
print(ta.result(), tb.result())
- выход из блока — только когда все задачи завершены;
- первая ошибка отменяет остальные задачи группы;
- все ошибки собираются в
ExceptionGroup.
Обработка ExceptionGroup:
try:
async with asyncio.TaskGroup() as tg: ...
except* TimeoutError as eg:
log.warning("таймауты: %s", eg.exceptions)
except* ValueError:
...
Выбор: новые проекты — TaskGroup: нет утечки задач и потерянных ошибок. gather — когда нужны частичные результаты при ошибках (return_exceptions=True) или код под Python < 3.11.