Порядок вывода в asyncio: create_task и await

Порядок вывода в asyncio: create_task и await

@python_quiz

Разберем этот квиз

Кратко — разберём, почему приведённая программа печатает строки именно в таком порядке и как работают планирование задач и отдача управления в asyncio.

Исходный код:

python

Ожидаемый вывод программы:

Почему так происходит (пошагово)

  1. main запускается и определяет inner.
  2. Выполняется print("A") — сразу выводит A.
  3. asyncio.create_task(inner()) создаёт и планирует задачу для inner. Это не запускает её синхронно прямо внутри текущей функции — задача поставлена в очередь планировщика событийного цикла и будет выполняться, когда управление вернётся в цикл.
  4. main продолжает и выполняет print("C") — выводит C.
  5. main выполняет await t — теперь main отдаёт управление циклу событий и ждёт завершения задачи inner.
  6. Цикл начинает выполнять планируемые задачи, запускает inner:

- inner сразу делает await asyncio.sleep(0). В asyncio sleep(0) означает "сдать ход обратно циклу и запланировать продолжение на следующую итерацию". inner при этом приостанавливается и возвращает управление в цикл.
- На следующей итерации inner возобновляется и выполняет print("B").

  1. inner завершается, await t в main возвращается, программа завершает работу.

Ключевые моменты

  • create_task не выполняет корутину немедленно в контексте вызывающей функции; она планируется и выполнится, когда цикл получит управление.
  • await внутри корутин отдаёт управление обратно циклу, позволяя выполняться другим задачам.
  • asyncio.sleep(0) — удобный способ явно уступить ход (yield) контролю цикла без заметной задержки.

Анализ вариантов ответа

  • "A, C, B" — соответствует порядку, описанному выше.
  • "A, B, C" — неправильно, потому что inner не может напечатать B до того, как main завершит текущую последовательность команд (в частности, печать C).
  • "B, A, C" — неправильно: inner не запускается до того, как main напечатает A и C.
  • "C, A, B" — тоже неверно: A печатается до создания задачи.

Наглядная проверка
Запустите скрипт — он напечатает A, затем C, затем B.

Выводы и советы

  • При отладке конкурентного кода учитывайте, что create_task лишь планирует задачу — она не прерывает текущую корутину.
  • Для явной передачи управления используйте await asyncio.sleep(0) или await asyncio.sleep(условие), либо просто await на события/завершение задач.
  • Если нужно, чтобы планируемая задача начала работу до дальнейших инструкций в той же корутине, придётся явно уступить ход (через await) или изменить логику так, чтобы это было гарантировано.

Report Page