Получить доступ

Как в asyncio работают отмена задач и таймауты?

MiddleКонкурентностьasyncioPython >=3.11
Ещё спрашивают так:
  • Что такое CancelledError и можно ли его перехватывать?
  • Как ограничить время выполнения корутины?
Коротко

task.cancel() бросает CancelledError внутрь корутины в точке ближайшего await. Таймаут — asyncio.timeout() (3.11) или wait_for: по истечении задача отменяется, наружу — TimeoutError. CancelledError нельзя глотать: очистить ресурсы и пробросить дальше.

  • CancelledError наследует BaseException (3.8+) — except Exception его не ловит
  • Очистка — в finally или async with
  • asyncio.shield защищает внутреннюю операцию от отмены внешней

А ещё Синхронный код без await отменить нельзя — отмена сработает только на следующем await

Так подсказку видит пользователь sotto на живом собеседовании — за пару секунд, пока вы думаете вслух.

Подробно

Механика. cancel() лишь помечает задачу; при следующем шаге в неё бросается CancelledError из того await, на котором она стоит. Корутина может выполнить очистку:

async def worker():
    conn = await pool.acquire()
    try:
        await conn.execute(...)
    finally:
        await pool.release(conn)    # выполнится и при отмене

Глотать нельзя. Если поймать CancelledError и не пробросить, вызывающий будет считать, что задача отменена, а она продолжит работу; TaskGroup и asyncio.timeout сломаются. Поймали для логирования — raise в конце.

Таймауты:

async with asyncio.timeout(2):       # Python 3.11
    await fetch()
# или
await asyncio.wait_for(fetch(), timeout=2)

При истечении внутренняя задача отменяется, наружу выходит TimeoutError.

shield. await asyncio.shield(save()) — внешняя отмена не прервёт сохранение, но вызывающий всё равно получит CancelledError.

Практика: таймаут на каждый внешний вызов; отмена распространяется сверху вниз — при отключении клиента фреймворк отменяет обработчик, и это должно корректно освобождать ресурсы.

Что хотят услышать

  • Как доставляется отмена.
  • Очистка ресурсов и запрет глотать CancelledError.
  • asyncio.timeout и wait_for.

Частые ошибки

  • except Exception: pass вокруг await — под Python 3.7 съедал и отмену.
  • Таймаут без отмены внутренней операции (запрос продолжает висеть).

Связанные вопросы

Закрытая бета

Подсказки на собеседовании — в реальном времени

sotto слышит вопрос интервьюера и показывает короткий ответ и план, как в блоке «Коротко». Оставьте контакт — пришлём доступ и промокод.

  • Промокод на 2 часа — сверх пробных 30 минут
  • Программа для Windows — скачать сразу, войти — через Яндекс ID или VK ID
  • Прямая связь с разработчиком: что улучшить — сделаем