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