
CancelledError — не просто очередная ошибка. Разбираемся, как устроена отмена задач в asyncio
StanislavShimovolos только что CancelledError — не просто очередная ошибка. Разбираемся, как устроена отмена задач в asyncio Средний 18 мин 31 Блог компании Точка Банк Python * Управление разработкой * Программирование...
Anthropic — What company has the best second artificial intelligence model at the end of June?
Значимый прорыв формирует отрасль ИИ: StanislavShimovolos только что CancelledError — не просто очередная ошибка. Разбираемся, как устроена отмена задач в asyncio Средний 18 мин 31 Блог компании Точка Банк Python * Управление разработкой * Программирование * Веб-разработка * При работе с асинхронным кодом нам часто приходится обрабатывать CancelledError — сигнал отмены задачи. С точки зрения приложения это выглядит как обычное исключение — достаточно добавить try/except блок и продолжить работу.
Хотя в большинстве случаев это и правда работает, иногда все же приходится копнуть глубже и разобраться, как устроен механизм отмены под капотом и для чего на самом деле нужен CancelledError. Впервые я столкнулся с такой потребностью при работе над FastAPI-сервисом для стриминга ответов от LLM. Запросы обрабатывались долго, и клиенты часто закрывали соединения, не дожидаясь ответа.
Технические детали
В таких случаях некорректная обработка дисконнектов приводила к зависшим транзакциям, сломанному пулу соединений с БД, а также к неэффективной утилизации ресурсов. Подробнее об этом — в прошлой статье: в ней детальный разбор того, что происходит при обрыве соединения, от уровня TCP до ASGI и кода вашего приложения. В тот момент казалось, что проблема решена: стало понятно, что стоит за дисконнектами, как они устроены и к чему приводят.
В конце концов, с точки зрения приложения дисконнект выглядит просто как отмена обработчика запроса — тот самый CancelledError. Однако не все так просто. В процессе реализации появляются новые вопросы.
Какой код отменять безопасно, а какой нет? Как не засорить весь код, включая бизнес-логику, однотипными обработчиками отмены? Что делать, когда есть несколько источников отмены — например, задача одновременно прерывается из-за таймаута и дисконнекта пользователя?
Отраслевые последствия
Это первая из двух статей, посвященных механике отмены задач. В ней мы остановимся на стандартном asyncio. Узнаем, что на самом деле представляет собой CancelledError с точки зрения event-loop.
Разберемся, как работает счетчик отмены (cancel/uncancel), на котором построены TaskGroup и asyncio. Наконец, обсудим проблемы, которые возникают на практике, в первую очередь связанные с asyncio. Во второй части мы посмотрим на более высокоуровневые примитивы из anyio и trio, а также на способы достичь похожих результатов на «чистом» asyncio.
Далее в рамках статьи приводятся ссылки на исходный код CPython версии 3. 0 логика отмены задач существенным образом не менялась, по этой причине все сказанное актуально для любой версии Python начиная с 3. Сниппеты кода представляют собой упрощенный вариант реализации механики отмены задач CPython: Lib/asyncio/tasks.
Событие, по словам экспертов, усилит конкуренцию в сфере ИИ.





