Бегуны¶
Исходный код: Lib/asyncio/runners.py
В этом разделе описываются высокоуровневые асинхронные примитивы для запуска асинхронного кода.
Они построены поверх event loop с целью упростить использование асинхронного кода для распространенных сценариев.
Запуск асинхронной программы¶
- asyncio.run(coro, *, debug=None)¶
Выполните команду coroutine coro и верните результат.
Эта функция запускает переданную сопрограмму, управляя циклом обработки событий asyncio, завершая работу асинхронных генераторов и закрывая пул потоков.
Эта функция не может быть вызвана, когда в том же потоке выполняется другой цикл обработки событий asyncio.
Если значение debug равно
True
, цикл обработки событий будет выполняться в режиме отладки.False
явно отключает режим отладки.None
используется для соблюдения глобальных настроек Режим отладки.Эта функция всегда создает новый цикл обработки событий и закрывает его в конце. Она должна использоваться в качестве основной точки входа для программ asyncio и в идеале должна вызываться только один раз.
Пример:
async def main(): await asyncio.sleep(1) print('hello') asyncio.run(main())
Добавлено в версии 3.7.
Изменено в версии 3.9: Обновлено для использования
loop.shutdown_default_executor()
.Изменено в версии 3.10: debug по умолчанию имеет значение
None
для соблюдения глобальных настроек режима отладки.
Контекстный менеджер бегуна¶
- class asyncio.Runner(*, debug=None, loop_factory=None)¶
Контекстный менеджер, который упрощает * несколько* асинхронных вызовов функций в одном контексте.
Иногда несколько асинхронных функций верхнего уровня должны вызываться в одних и тех же event loop и
contextvars.Context
.Если значение debug равно
True
, цикл обработки событий будет выполняться в режиме отладки.False
явно отключает режим отладки.None
используется для соблюдения глобальных настроек Режим отладки.loop_factory может использоваться для переопределения создания цикла. В обязанности loop_factory входит установка созданного цикла в качестве текущего. По умолчанию используется
asyncio.new_event_loop()
и устанавливается в качестве текущего цикла обработки событий сasyncio.set_event_loop()
, если loop_factory равенNone
.В принципе, пример
asyncio.run()
можно переписать с использованием runner:async def main(): await asyncio.sleep(1) print('hello') with asyncio.Runner() as runner: runner.run(main())
Добавлено в версии 3.11.
- run(coro, *, context=None)¶
Запустите coroutine coro во встроенном цикле.
Верните результат сопрограммы или вызовите ее исключение.
Необязательный аргумент context, содержащий только ключевое слово, позволяет указать пользовательский
contextvars.Context
, в котором будет выполняться coro. ЕслиNone
, используется контекст программы по умолчанию.Эта функция не может быть вызвана, когда в том же потоке выполняется другой цикл обработки событий asyncio.
- close()¶
Закройте дверцу.
Завершите работу асинхронных генераторов, выключите default executor, закройте цикл обработки событий и выпустите встроенный
contextvars.Context
.
- get_loop()¶
Возвращает цикл обработки событий, связанный с экземпляром runner.
Примечание
Runner
использует стратегию ленивой инициализации, ее конструктор не инициализирует базовые низкоуровневые структуры.Встроенные цикл и контекст создаются при вводе основного текста
with
или при первом вызовеrun()
илиget_loop()
.
Обработка прерывания работы клавиатуры¶
Добавлено в версии 3.11.
Когда signal.SIGINT
вызывается с помощью Ctrl-C, KeyboardInterrupt
по умолчанию в главном потоке возникает исключение. Однако это не работает с asyncio
, потому что это может прервать работу внутренних компонентов asyncio и может привести к зависанию программы при выходе.
Чтобы устранить эту проблему, asyncio
обрабатывает signal.SIGINT
следующим образом:
asyncio.Runner.run()
устанавливает пользовательский обработчикsignal.SIGINT
перед выполнением любого пользовательского кода и удаляет его при выходе из функции.Runner
создает основную задачу для переданной сопрограммы для ее выполнения.Когда
signal.SIGINT
вызывается Ctrl-C, пользовательский обработчик сигнала отменяет основную задачу, вызываяasyncio.Task.cancel()
, который вызываетasyncio.CancelledError
внутри основной задачи. Это приводит к раскручиванию стека Python, и блокиtry/except
иtry/finally
могут быть использованы для очистки ресурсов. После отмены основной задачиasyncio.Runner.run()
вызываетKeyboardInterrupt
.Пользователь мог бы написать замкнутый цикл, который не может быть прерван
asyncio.Task.cancel()
, и в этом случае второй следующий Ctrl-C немедленно вызываетKeyboardInterrupt
, не отменяя основную задачу.