Содержание страницы
Исполнители¶Runners
Исходный код: Lib/asyncio/runners.py
В этом разделе описываются высокоуровневые примитивы asyncio для выполнения асинхронного кода.
Они построены поверх цикла событий с целью упростить использование асинхронного кода в распространённых сценариях.
Запуск программы asyncio¶Running an asyncio Program
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
Выполняет корутину coro и возвращает результат.
Эта функция запускает переданную корутину, заботясь об управлении циклом событий 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.
Контекстный менеджер 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.12.
- 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.12.
Когда 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без отмены главной задачи.