async· 4 мин

asyncio.gather и обработка ошибок

У asyncio.gather есть две заметно разные модели поведения, и выбор между ними легко пропустить.

По умолчанию: первая ошибка «всплывает»

Если любая из корутин бросит исключение, gather немедленно пробросит его наверх. Остальные задачи при этом не отменяются автоматически — они продолжат выполняться в фоне, и про них легко забыть.

import asyncio

async def main():
    await asyncio.gather(task_a(), task_b(), task_c())

return_exceptions=True

С этим флагом gather дождётся всех корутин и вернёт список, где на месте упавших задач будут сами объекты исключений. Удобно, когда частичный успех допустим:

results = await asyncio.gather(*tasks, return_exceptions=True)
for r in results:
    if isinstance(r, Exception):
        log.warning("задача упала: %r", r)

А что в 3.11+

Если нужна семантика «всё или ничего» с гарантированной отменой остальных задач при ошибке — берите asyncio.TaskGroup. Он отменяет соседние задачи и собирает ошибки в ExceptionGroup.

← ко всем заметкам