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

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

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

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

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

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

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

Выполняет coro в цикле событий asyncio и возвращает результат.

Аргументом может быть любой ожидаемый объект.

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

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

Если debug равен True, цикл событий будет работать в режиме отладки. False явно отключает режим отладки. None используется для соблюдения глобальных настроек режима отладки.

Если loop_factory не равен None, он используется для создания нового цикла событий; в противном случае используется asyncio.new_event_loop(). Цикл закрывается в конце. Эта функция должна использоваться как основная точка входа для программ asyncio, и в идеале её следует вызывать только один раз. Рекомендуется использовать loop_factory для настройки цикла событий.

Исполнителю даётся тайм-аут в 5 минут для завершения. Если исполнитель не завершился за это время, выводится предупреждение и исполнитель закрывается.

Пример:

async def main():
    await asyncio.sleep(1)
    print('hello')

asyncio.run(main())

Добавлено в версии 3.7.

Изменено в версии 3.9: Обновлено для использования loop.shutdown_default_executor().

Изменено в версии 3.10: debug по умолчанию равен None, чтобы соблюдать глобальные настройки режима отладки.

Изменено в версии 3.12: Добавлен параметр loop_factory.

Изменено в версии 3.14: coro может быть любым ожидаемым объектом.

Контекстный менеджер 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.12.

run(coro, *, context=None)

Выполняет coro во встроенном цикле событий.

Аргументом может быть любой ожидаемый объект.

Если аргумент является корутиной, он оборачивается в задачу.

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

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

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

Изменено в версии 3.14: coro может быть любым ожидаемым объектом.

close()

Закрывает runner.

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

get_loop()

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

Примечание

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

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

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

Добавлено в версии 3.12.

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