Порядок вывода в asyncio: create_task и await
@python_quizРазберем этот квиз
Кратко — разберём, почему приведённая программа печатает строки именно в таком порядке и как работают планирование задач и отдача управления в asyncio.
Исходный код:

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

Почему так происходит (пошагово)
- main запускается и определяет inner.
- Выполняется print("A") — сразу выводит A.
- asyncio.create_task(inner()) создаёт и планирует задачу для inner. Это не запускает её синхронно прямо внутри текущей функции — задача поставлена в очередь планировщика событийного цикла и будет выполняться, когда управление вернётся в цикл.
- main продолжает и выполняет print("C") — выводит C.
- main выполняет await t — теперь main отдаёт управление циклу событий и ждёт завершения задачи inner.
- Цикл начинает выполнять планируемые задачи, запускает inner:
- inner сразу делает await asyncio.sleep(0). В asyncio sleep(0) означает "сдать ход обратно циклу и запланировать продолжение на следующую итерацию". inner при этом приостанавливается и возвращает управление в цикл.
- На следующей итерации inner возобновляется и выполняет print("B").
- 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) или изменить логику так, чтобы это было гарантировано.