Бегуны¶
Источник: Lib/asyncio/runners.py
В этом разделе описаны высокоуровневые примитивы asyncio для выполнения кода asyncio.
Они строятся поверх event loop с целью упростить использование асинхронного кода в распространенных сценариях.
Запуск программы asyncio¶
- asyncio.run(coro, *, debug=None, loop_factory=None)¶
Выполните coroutine coro и верните результат.
Эта функция запускает переданную корутину, заботясь об управлении циклом событий asyncio, завершении работы асинхронных генераторов и закрытии исполнителя.
Эта функция не может быть вызвана, если в том же потоке запущен другой цикл событий asyncio.
Если значение debug равно
True
, цикл событий будет выполняться в режиме отладки.False
отключает режим отладки в явном виде.None
используется для соблюдения глобальных настроек Режим отладки.Если loop_factory не
None
, то он используется для создания нового цикла событий; в противном случае используетсяasyncio.new_event_loop()
. В конце цикл закрывается. Эта функция должна использоваться в качестве основной точки входа для программ asyncio, и в идеале должна вызываться только один раз. Рекомендуется использовать loop_factory для настройки цикла событий вместо политик. Передачаasyncio.EventLoop
позволяет запускать asyncio без системы политик.Исполнителю дается таймаут на выключение продолжительностью 5 минут. Если исполнитель не завершил работу в течение этого времени, выдается предупреждение и исполнитель закрывается.
Пример:
async def main(): await asyncio.sleep(1) print('hello') asyncio.run(main())
Added in version 3.7.
Изменено в версии 3.9: Обновлено для использования
loop.shutdown_default_executor()
.Изменено в версии 3.10: По умолчанию значение debug равно
None
, чтобы соблюдались глобальные настройки режима отладки.Изменено в версии 3.12: Добавлен параметр loop_factory.
Менеджер контекста бегуна¶
- class asyncio.Runner(*, debug=None, loop_factory=None)¶
Менеджер контекста, который упрощает многочисленные вызовы асинхронных функций в одном и том же контексте.
Иногда несколько асинхронных функций верхнего уровня должны вызываться в одних и тех же event loop и
contextvars.Context
.Если значение debug равно
True
, цикл событий будет выполняться в режиме отладки.False
отключает режим отладки в явном виде.None
используется для соблюдения глобальных настроек Режим отладки.Для переопределения создания цикла можно использовать loop_factory. В обязанности loop_factory входит установка созданного цикла в качестве текущего. По умолчанию используется
asyncio.new_event_loop()
, который устанавливается в качестве текущего цикла события, а если loop_factory -None
, тоasyncio.set_event_loop()
.В принципе, пример
asyncio.run()
можно переписать с использованием бегунка:async def main(): await asyncio.sleep(1) print('hello') with asyncio.Runner() as runner: runner.run(main())
Added in version 3.11.
- run(coro, *, context=None)¶
Выполните coroutine coro во встроенном цикле.
Возвращает результат работы корутины или поднимает ее исключение.
Необязательный аргумент context, содержащий только ключевое слово, позволяет указать пользовательский
contextvars.Context
для запуска coro. ЕслиNone
, то используется контекст по умолчанию.Эта функция не может быть вызвана, если в том же потоке запущен другой цикл событий asyncio.
- close()¶
Закройте бегунок.
Завершение работы асинхронных генераторов, выключение исполнителя по умолчанию, закрытие цикла событий и освобождение встроенного
contextvars.Context
.
- get_loop()¶
Возвращает цикл событий, связанный с экземпляром бегуна.
Примечание
Runner
использует стратегию ленивой инициализации, его конструктор не инициализирует базовые низкоуровневые структуры.Вложенные петля и контекст создаются при входе в тело
with
или при первом вызовеrun()
илиget_loop()
.
Обработка прерывания клавиатуры¶
Added in version 3.11.
Когда signal.SIGINT
поднимается Ctrl-C, исключение KeyboardInterrupt
по умолчанию поднимается в главном потоке. Однако это не работает с asyncio
, поскольку может прервать работу внутренних функций asyncio и привести к зависанию программы при выходе из нее.
Чтобы смягчить эту проблему, asyncio
обрабатывает signal.SIGINT
следующим образом:
asyncio.Runner.run()
устанавливает пользовательский обработчикsignal.SIGINT
до выполнения любого пользовательского кода и удаляет его при выходе из функции.Параметр
Runner
создает главную задачу для переданной coroutine для ее выполнения.Когда
signal.SIGINT
поднимается Ctrl-C, пользовательский обработчик сигналов отменяет основную задачу, вызываяasyncio.Task.cancel()
, который поднимаетasyncio.CancelledError
внутри основной задачи. Это приводит к разворачиванию стека Python, блокиtry/except
иtry/finally
могут быть использованы для очистки ресурсов. После отмены основной задачиasyncio.Runner.run()
поднимаетKeyboardInterrupt
.Пользователь может написать жесткий цикл, который не может быть прерван
asyncio.Task.cancel()
, в этом случае второй следующий Ctrl-C немедленно поднимаетKeyboardInterrupt
, не отменяя основную задачу.