Перейти к содержимому

Runners

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

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

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

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

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 для настройки цикла событий вместо политик. Передача asyncio.EventLoop позволяет запускать asyncio без системы политик.

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

Пример:

python
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 может быть любым ожидаемым объектом.

Примечание

Система политик asyncio устарела и будет удалена в Python 3.16; начиная с этой версии, для настройки цикла событий потребуется явный loop_factory.

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

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:

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

with asyncio.Runner() as runner:
    runner.run(main())

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

run(coro, *, context=None)

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

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

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

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

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

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

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

close()

Закрывает исполнитель.

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

get_loop()

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

Примечание

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