Документация Python неофициальный перевод
Содержание страницы

ИсполнителиRunners

Исходный код: Lib/asyncio/runners.py

В этом разделе описываются высокоуровневые примитивы asyncio для выполнения асинхронного кода.

Они построены поверх цикла событий с целью упростить использование асинхронного кода в распространённых сценариях.

Запуск программы asyncioRunning an asyncio Program

asyncio.run(coro, *, debug=None)

Выполняет корутину 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, чтобы соблюдать глобальные настройки режима отладки.

Контекстный менеджер RunnerRunner context manager

class asyncio.Runner(*, debug=None, loop_factory=None)

Контекстный менеджер, упрощающий множественные вызовы асинхронных функций в одном контексте.

Иногда несколько асинхронных функций верхнего уровня нужно вызывать в одном цикле событий и 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)

Запускает корутину coro во встроенном цикле событий.

Возвращает результат корутины или возбуждает её исключение.

Необязательный аргумент context (только по ключу) позволяет указать пользовательский contextvars.Context для выполнения coro. Если None, используется контекст запускатора по умолчанию.

Эту функцию нельзя вызывать, когда в том же потоке выполняется другой цикл событий asyncio.

close()

Закрывает runner.

Завершает асинхронные генераторы, останавливает исполнитель по умолчанию, закрывает цикл событий и освобождает встроенный contextvars.Context.

get_loop()

Возвращает цикл событий, связанный с экземпляром runner.

Примечание

Runner использует стратегию ленивой инициализации: его конструктор не инициализирует нижележащие низкоуровневые структуры.

Встроенные цикл событий и контекст создаются при входе в тело with или при первом вызове run() или get_loop().

Обработка прерывания с клавиатурыHandling Keyboard Interruption

Новое в версии 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 без отмены главной задачи.