asyncio: get_running_loop внутри run_until_complete

asyncio: get_running_loop внутри run_until_complete

@python_quiz

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

Коротко — программа напечатает True. Ниже разберём почему, пошагово разберём варианты ответов и покажем небольшие примеры.

Условие (код)

python

Что происходит шаг за шагом

  1. Создаётся новый цикл событий loop = asyncio.new_event_loop().
  2. asyncio.set_event_loop(loop) назначает этот цикл как "текущий" в контексте модуля asyncio (в этой нити).
  3. Запускаем корутину main на созданном цикле через loop.run_until_complete(main()). На время выполнения run_until_complete цикл считается запущенным.
  4. Внутри main() вызывается asyncio.get_running_loop(). Эта функция возвращает *запущенный* цикл событий в текущей нити — то, на котором реально выполняется корутина.
  5. Так как мы запускаем main() именно на объекте loop, сравнение asyncio.get_running_loop() is loop даст True.

Почему не False и не RuntimeError

  • False бы получилось только если внутри корутины был бы запущен другой цикл или get_running_loop() вернул бы другой объект (например, если бы корутина выполнялась на другом loop), чего тут не происходит.
  • RuntimeError возникает, когда пытаются получить "запущенный" цикл там, где он не запущен (например, вызов asyncio.get_running_loop() в обычной функции вне запущенного цикла). В данном коде вызов происходит внутри корутины, запущенной через run_until_complete, поэтому ошибки не будет.
  • Вызов set_event_loop(loop) здесь не обязателен для получения True: даже если не вызывать set_event_loop, вызов loop.run_until_complete(main()) делает loop запущенным для текущей нити, и внутри корутины get_running_loop() вернёт тот же loop.

Разбор вариантов (коротко)

  • Выведет False — неправдоподобно для данного кода, потому что запущенный цикл — тот же объект loop.
  • Выведет True — соответствует описанному поведению: внутри запущенной корутины get_running_loop() возвращает запущенный цикл.
  • Поднимет RuntimeError до запуска main() — не соответствует: RuntimeError для get_running_loop возникает при вызове вне запущенного цикла, но в коде вызов происходит внутри уже запускаемого цикла.
  • Поднимет RuntimeError внутри main() — не происходит, так как внутри main() цикл запущен.

Наглядные примеры

Оригинальный код — печатает True:

python

Вызов get_running_loop вне запущенного цикла — RuntimeError:

python

Альтернатива с get_event_loop (поведение зависит от версии Python и контекста):

python

Итог

В рассматриваемом коде внутри выполняющейся корутины вызывается asyncio.get_running_loop(), и поскольку корутина запущена на объекте loop, сравнение с loop вернёт True. Важно понимать разницу между "текущим" циклом (set_event_loop / get_event_loop) и именно "запущенным" циклом (get_running_loop), особенно при отладке ошибок вида RuntimeError: no running event loop.

Report Page