Бегуны

Исходный код: 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 следующим образом:

  1. asyncio.Runner.run() устанавливает пользовательский обработчик signal.SIGINT перед выполнением любого пользовательского кода и удаляет его при выходе из функции.

  2. Runner создает основную задачу для переданной сопрограммы для ее выполнения.

  3. Когда signal.SIGINT вызывается Ctrl-C, пользовательский обработчик сигнала отменяет основную задачу, вызывая asyncio.Task.cancel(), который вызывает asyncio.CancelledError внутри основной задачи. Это приводит к раскручиванию стека Python, и блоки try/except и try/finally могут быть использованы для очистки ресурсов. После отмены основной задачи asyncio.Runner.run() вызывает KeyboardInterrupt.

  4. Пользователь мог бы написать замкнутый цикл, который не может быть прерван asyncio.Task.cancel(), и в этом случае второй следующий Ctrl-C немедленно вызывает KeyboardInterrupt, не отменяя основную задачу.

Вернуться на верх