Вопрос с собеседования · Python

Как работают async и await?

JuniorКонкурентностьasyncio
Ещё спрашивают так:
  • Что такое корутина?
  • Что такое event loop?
  • Как запустить несколько корутин одновременно?
Коротко

async def создаёт корутину, await — точка, где она отдаёт управление циклу событий, пока ждёт.

  • Цикл событий переключается между корутинами в точках await — в одном потоке
  • Одновременный запуск: asyncio.gather или asyncio.TaskGroup (3.11+)

А ещё Блокирующий вызов (time.sleep, синхронный HTTP) останавливает все корутины

Подробно

Вызов функции, объявленной через async def, не выполняет её тело, а возвращает объект-корутину. Выполнить его можно через await внутри другой корутины или запустив цикл событий: asyncio.run(main()).

Цикл событий (event loop) держит список задач. Корутина выполняется до ближайшего await на операции, которая ещё не готова (ответ сети, таймер). Там она приостанавливается, цикл запускает другую готовую задачу, а когда операция завершается — продолжает первую с того же места. Переключение кооперативное: корутина сама решает, где уступить, и только в await.

Одновременность. Последовательные await a(); await b() идут друг за другом. Чтобы задачи шли параллельно, их оборачивают в задачи: asyncio.gather(a(), b()), asyncio.create_task(...) или TaskGroup — последний правильно отменяет остальные задачи при ошибке.

Ограничения. await можно писать только внутри async def. Всё блокирующее внутри корутины останавливает цикл целиком: вместо time.sleep — asyncio.sleep, вместо requests — aiohttp или httpx. Блокирующий код, без которого не обойтись, выносят в поток: await asyncio.to_thread(func).

asyncio не ускоряет вычисления — это способ эффективно ждать много операций ввода-вывода.

Пример

import asyncio

async def fetch(name, delay):
    await asyncio.sleep(delay)          # не блокирует другие корутины
    return f"{name} готов"

async def main():
    # последовательно — 3 секунды
    await fetch("a", 1)
    await fetch("b", 2)

    # параллельно — 2 секунды
    results = await asyncio.gather(fetch("a", 1), fetch("b", 2))
    print(results)

asyncio.run(main())

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

  • Что такое корутина и что вызов async def её только создаёт.
  • Роль цикла событий и кооперативное переключение в await.
  • Как запустить задачи параллельно.
  • Опасность блокирующих вызовов и способ их вынести.

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

  • Забыть await — корутина не выполнится, будет предупреждение.
  • Ожидать, что asyncio ускорит вычисления на CPU.

Проверьте себя

Один верный вариант. Подумайте, потом откройте ответ.

Показать варианты и ответ
  • ✗async def запускает функцию в отдельном потоке, а await ждёт её завершения
  • ✓async def создаёт корутину, await — точка, где она отдаёт управление циклу событий
  • ✗time.sleep внутри корутины отдаёт управление другим корутинам
  • ✗await создаёт новый процесс для ожидания

Что спросят дальше

Разбор темы

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

Партнёр платформы

Разбор собеседования с sotto

После собеседования sotto разбирает разговор: оценка, каждый вопрос — хорошо, частично или слабо, чего не хватило в ответе и над чем поработать к следующему разу. Первые 30 минут бесплатно.

Разбор собеседования