> Что такое coroutine и как он работает в Python (Python)
Уровень: junior · Роль: backend · Язык: Python · Категория: Технические вопросы
Компании: Домклик, Sunlight
Стек: Python
> Пример ответа
Короткий ответ
Coroutine - это функция, выполнение которой можно приостановить и возобновить позже, сохраняя её состояние. В Python coroutine создаётся через async def и управляется event loop. В отличие от обычной функции, coroutine не выполняется сразу при вызове - она возвращает объект coroutine, который нужно запустить через await или event loop. Это позволяет писать конкурентный код без многопоточности, эффективно работая с I/O-bound задачами.
Подробное объяснение
Coroutine в Python - это специальный вид функции, определённой с помощью async def. При вызове такая функция не выполняет своё тело, а возвращает объект coroutine. Выполнение начинается только когда coroutine передаётся в event loop или вызывается через await.
Ключевые механизмы:
await- приостанавливает выполнение coroutine до завершения другой awaitable-операции (другой coroutine, Future, Task). В моментawaitуправление возвращается в event loop.- Event loop - центральный диспетчер, который отслеживает состояние всех coroutine и переключает выполнение между ними, когда одна из них блокируется на I/O.
- Task - обёртка над coroutine, которая планирует её выполнение в event loop. Создаётся через
asyncio.create_task(). - State - состояние coroutine (локальные переменные, счётчик команд) сохраняется между приостановками, поэтому при возобновлении выполнение продолжается с места последнего
await.
Отличие от генераторов: генераторы тоже приостанавливаются через yield, но coroutine предназначены для конкурентного выполнения и управляются event loop, а не вручную через next().
На практике
В backend-разработке coroutine используются для обработки множества одновременных I/O операций: HTTP-запросов, работы с БД, чтения файлов. Например, веб-сервер на FastAPI или aiohttp обрабатывает тысячи соединений в одном потоке, переключаясь между coroutine, когда одна из них ожидает ответа от БД или внешнего API.
Важно понимать: coroutine не ускоряют CPU-bound задачи. Если внутри coroutine выполняется тяжёлая синхронная работа, она заблокирует весь event loop. Для CPU-bound задач нужны отдельные процессы или потоки.
Пример кода
PYTHONimport asyncioasync def fetch_data(url):print(f"Начало загрузки {url}")await asyncio.sleep(1) # имитация I/O операцииprint(f"Загрузка {url} завершена")return f"Данные из {url}"async def main():# Создаём две задачи, которые выполняются конкурентноtask1 = asyncio.create_task(fetch_data("url1"))task2 = asyncio.create_task(fetch_data("url2"))# Ожидаем завершения обеих задачresults = await asyncio.gather(task1, task2)print(results)asyncio.run(main())
Вывод:
Начало загрузки url1 Начало загрузки url2 Загрузка url1 завершена Загрузка url2 завершена ['Данные из url1', 'Данные из url2']
Обратите внимание: обе загрузки стартуют одновременно, а не последовательно.
Как отвечать на собеседовании
Начните с простого определения, затем покажите понимание механики: async def, await, event loop. Обязательно упомяните, что coroutine - это не поток и не процесс, а способ конкурентного выполнения в одном потоке. Приведите пример из практики: обработка HTTP-запросов в FastAPI. Если спросят про отличие от генераторов - скажите, что генераторы управляются вручную через next(), а coroutine - через event loop. Хорошо показать понимание ограничений: coroutine не помогают для CPU-bound задач.
Что проверяет интервьюер
Интервьюер проверяет:
- Понимаете ли вы разницу между синхронным и асинхронным кодом.
- Знаете ли вы, как создаётся coroutine (
async def) и как запускается (await,asyncio.run,create_task). - Понимаете ли вы роль event loop и почему
awaitпередаёт управление. - Понимаете ли вы, что coroutine - это не магия, а механизм кооперативной многозадачности: coroutine сама решает, когда приостановиться.
- Умеете ли вы объяснить, когда coroutine полезны, а когда нет.
Типичные ошибки
- Забывают про
await: вызовfetch_data("url")безawaitпросто создаёт объект coroutine, но не выполняет его. Это частая ошибка новичков. - Путают coroutine с потоками: coroutine выполняются в одном потоке, поэтому нет гонок данных, но и нет параллелизма для CPU-bound задач.
- Блокируют event loop: вызов
time.sleep()или синхронного requests внутри coroutine блокирует все остальные coroutine. Нужно использоватьasyncio.sleep()и асинхронные библиотеки. - Не используют
create_task: если просто написатьawait fetch_data("url1")и затемawait fetch_data("url2"), они выполнятся последовательно, а не конкурентно. - Не понимают, что
asyncio.run()создаёт и закрывает event loop: нельзя вызыватьasyncio.run()внутри уже работающего event loop.
> Похожие задачи по Python
Какие HTTP статусы существуют и каково назначение 2xx, 3xx, 4xx, 5xx
Как происходит передача аргументов в функцию в Python
В каком порядке строить составной индекс для user_id и даты
Что такое контейнеризация и зачем она нужна
> Похожие задачи по backend
Как происходит передача аргументов в функцию в Python
В чем разница между процессом и потоком и какова их иерархия?
В каком порядке строить составной индекс для user_id и даты
Что такое контейнеризация и зачем она нужна
> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?
Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью