Содержание страницы
Исполнители¶Runners
Исходный код: Lib/asyncio/runners.py
В этом разделе описываются высокоуровневые примитивы asyncio для выполнения асинхронного кода.
Они построены поверх цикла событий с целью упростить использование асинхронного кода в распространённых сценариях.
Запуск программы asyncio¶Running 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, чтобы соблюдать глобальные настройки режима отладки.
Контекстный менеджер Runner¶Runner 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 следующим образом:
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без отмены главной задачи.