---
title: Асинхронность и asyncio
questionDates:
  q-transfer-0171: '2026-10-01'
  q-transfer-0172: '2026-10-01'
  q-transfer-0173: '2026-10-01'
  q-transfer-0174: '2026-10-01'
  q-transfer-0175: '2026-10-01'
  q-transfer-0176: '2026-10-01'
  q-transfer-0177: '2026-10-01'
  q-transfer-0178: '2026-10-01'
  q-transfer-0179: '2026-10-01'
  q-transfer-0232: '2026-10-01'
  q-transfer-0233: '2026-10-01'
  q-transfer-0268: '2026-10-01'
seo:
  description: >-
    Тема «Асинхронность и asyncio» для собеседования Python Developer. Что
    делает await и чего он не делает? Как event loop планирует корутины?
  title: Асинхронность и asyncio — Python Developer
---

[Все темы Python Developer](/prep/python-developer)

## Что делает await и чего он не делает? [#q-transfer-0171]

`await` приостанавливает текущую корутину до завершения awaitable-объекта и позволяет циклу событий выполнять другую готовую работу. Состояние корутины сохраняется. Оператор сам не создает конкурентность и не переносит код в поток: последовательные `await` остаются последовательными. Для независимых операций создают управляемые задачи. Если вызываемая работа синхронно блокирует поток, `await` внутри нее не появится и event loop остановится. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Корутины и await: запуск и ожидание в asyncio](https://asyncio.ru/3.15/library/asyncio-task.html#coroutines)
   :::

---

## Как event loop планирует корутины? [#q-transfer-0172]

Event loop держит готовые callbacks и задачи, следит за I/O и таймерами. Корутина выполняется до точки, где `await` действительно должен ждать, затем управление получает цикл; после готовности операции задача снова попадает в очередь. Обычно все это происходит в одном потоке, поэтому долгий синхронный вызов задерживает всех. Планировщик обеспечивает конкурентное продвижение, но не обещает строгую справедливость или параллельность Python-кода. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Как event loop продвигает Task: ожидание Future, таймеры и пробуждение — Точка Банк](https://habr.com/ru/companies/tochka/articles/1048468/)
2. [Event loop. Кирилл Македонский, с 10:24](https://www.youtube.com/watch?v=cDXzxd9Nf7o&t=624s)

:::

---

## Что такое корутина и как она запускается? [#q-transfer-0173]

Функция `async def` при вызове возвращает объект-корутину, но ее тело еще не обязано выполняться. Корутину запускают через `await`, `asyncio.create_task()` внутри работающего цикла или верхнеуровневый `asyncio.run()`. Модель эффективна для множества операций ожидания, если используемые библиотеки неблокирующие. Вычисления без точек ожидания занимают поток event loop и требуют другого способа исполнения. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Корутины и способы запуска: await, create_task и run — русский перевод справочника Python](https://asyncio.ru/3.15/library/asyncio-task.html#coroutines)
   :::

---

## Зачем нужна asyncio.Task? [#q-transfer-0174]

`asyncio.create_task(coro)` оборачивает корутину в `Task` и планирует ее конкурентное выполнение. Task хранит состояние, результат или исключение, ее можно дождаться и запросить отмену. Ссылку на задачу сохраняют, а результат и ошибку обязательно собирают. Связанные задачи удобнее запускать в `TaskGroup`, который ждет всех и управляет сбоями. Массовый `create_task` ограничивают семафором, очередью или пулом ресурсов. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [asyncio.Task: создание задач, результат и TaskGroup](https://asyncio.ru/3.15/library/asyncio-task.html#creating-tasks)
2. [Task в asyncio. Кирилл Македонский, с 12:55](https://www.youtube.com/watch?v=cDXzxd9Nf7o&t=775s)

:::

---

## Почему CPU-bound код блокирует event loop? [#q-transfer-0175]

CPU-bound функция без `await` не возвращает управление event loop, поэтому таймеры, сокеты и остальные задачи ждут. Простое помещение вычисления в `async def` этого не меняет. Блокирующий вызов можно вынести через `asyncio.to_thread`, если библиотека освобождает GIL или работа в основном I/O. Для тяжелого чистого Python обычно выбирают процессы. В free-threaded сборках CPython свойства параллелизма и расширений нужно проверять отдельно. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Почему вычисления задерживают весь event loop и когда нужен executor — русский справочник asyncio](https://asyncio.ru/3.15/library/asyncio-dev.html#running-blocking-code)
2. [Почему CPU-bound код блокирует asyncio. Кирилл Македонский, с 1:06](https://www.youtube.com/watch?v=cDXzxd9Nf7o&t=66s)

:::

---

## Чем блокирующий I/O отличается от неблокирующего? [#q-transfer-0176]

Блокирующая операция удерживает поток до результата. Неблокирующий API регистрирует ожидание и позволяет потоку заняться другой работой, а готовность сообщает ОС или runtime. В `asyncio` синхронный файловый или сетевой клиент внутри `async def` все равно блокирует event loop. Поэтому важна не метка функции, а вся цепочка библиотек; несовместимый вызов заменяют async-клиентом или изолируют в ограниченном executor. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Блокирующий I/O внутри корутины и перенос через to_thread — русский справочник asyncio](https://asyncio.ru/3.15/library/asyncio-task.html#running-in-threads)
   :::

---

## Чем asyncio.Future отличается от Task? [#q-transfer-0177]

`Future` представляет будущий результат и бывает `pending`, завершенным или отмененным; кто-то другой устанавливает ему значение или исключение. `Task` является специализированным Future, который сам продвигает корутину при планировании event loop. Оба объекта можно `await` и отменять, но прикладной код редко создает Future вручную. Он чаще получает Task или Future от библиотеки и отвечает за сбор результата и исключения. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Future и Task: будущий результат и управление корутиной — русский справочник asyncio](https://asyncio.ru/3.15/library/asyncio-task.html#awaitables)
   :::

---

## Как реализовать асинхронный контекстный менеджер? [#q-transfer-0178]

Асинхронный менеджер реализует `async __aenter__` и `async __aexit__` либо создается через `@asynccontextmanager`. Получение ресурса идет до `yield`, значение передается в `async with`, а закрытие помещают в `finally` и можно выполнить через `await`. Исключение из тела приходит менеджеру; его обычно не подавляют. Операции входа и выхода тоже должны быть неблокирующими, иначе они остановят event loop. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Асинхронный контекстный менеджер через asynccontextmanager и finally — русский справочник Python](https://asyncio.ru/3.15/library/contextlib.html#contextlib.asynccontextmanager)
   :::

---

## Может ли возникнуть race condition в asyncio? [#q-transfer-0179]

Да. Корутины выполняются в одном потоке, но переключение на `await` между чтением и записью общего состояния позволяет другой задаче изменить его. Критическую секцию защищают `asyncio.Lock`, а передачу данных часто проще строить через `Queue` и одного владельца состояния. Lock внутри процесса не делает атомарной запись во внешнюю БД; там нужны транзакция, ограничение уникальности или условное обновление. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Потерянное обновление между корутинами — Точка Банк](https://habr.com/ru/companies/tochka/articles/865086/)
   :::

---

## Как контролировать жизненный цикл фоновой asyncio.Task? [#q-transfer-0232]

У фоновой Task должен быть владелец и срок жизни. Сохраняют сильную ссылку, собирают результат и исключение, а при остановке вызывают `cancel()` и затем `await`, давая `finally` закрыть ресурс. Таймаут ограничивает ожидание, но тоже реализуется отменой. Связанные задачи лучше держать в `TaskGroup`; бесконтрольный fire-and-forget теряет ошибки и может пережить запрос, которому задача принадлежала. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Фоновые задачи asyncio: сильные ссылки, отмена и очистка в finally](https://asyncio.ru/3.15/library/asyncio-task.html#task-cancellation)
   :::

---

## Где возникает backpressure в async-сервисе? [#q-transfer-0233]

Backpressure появляется там, где вход быстрее ограниченного ресурса: очередь запросов, пул БД, лимит внешнего API, сетевой буфер или consumer lag. Вместо создания неограниченного числа Task ставят bounded queue, semaphore и timeout, а при переполнении замедляют чтение или отклоняют работу. Наблюдают длину и возраст очереди, время ожидания ресурса, число отказов и utilization, иначе задержка скрыто растет до OOM. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Backpressure через ограниченную asyncio.Queue: ожидание места и размер очереди](https://asyncio.ru/3.15/library/asyncio-queue.html#asyncio.Queue)
   :::

---

## Когда синхронный код быстрее async? [#q-transfer-0268]

Синхронный код часто быстрее для короткой CPU-операции или последовательного сценария без конкурентного ожидания: у event loop, coroutine и Task есть накладные расходы. Async выигрывает throughput, когда много операций независимо ждут сеть или другой неблокирующий ресурс. Он не ускоряет одно вычисление и может ухудшить latency при блокирующей зависимости. Выбор подтверждают профилем нагрузки, а не самим наличием `async` API. Проверяют отмену и остановку сервиса, потому что успешное ожидание не доказывает корректный жизненный цикл ресурса.

:::note[Ссылки для изучения]

1. [Почему async не всегда быстрее: накладные расходы и характер нагрузки](https://habr.com/ru/articles/1011544/)
   :::
