> **Источник:** https://python-all.ru/3.14/library/asyncio-runner.html
>
> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.

---

# Исполнители

**Исходный код:** [Lib/asyncio/runners.py](https://python-all.ru/src/3.14/Lib/asyncio/runners.py)

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

Они построены поверх [цикла событий](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio-event-loop) с целью упростить использование асинхронного кода в распространённых сценариях.

[Запуск asyncio-программы](https://python-all.ru/3.14/library/asyncio-runner.html#running-an-asyncio-program) [Контекстный менеджер Runner](https://python-all.ru/3.14/library/asyncio-runner.html#runner-context-manager) [Обработка прерывания с клавиатуры](https://python-all.ru/3.14/library/asyncio-runner.html#handling-keyboard-interruption)

## [Запуск программы asyncio](https://python-all.ru/3.14/library/asyncio-runner.html#id1)

#### `asyncio.run(coro, *, debug=None, loop_factory=None)`

Выполняет *coro* в цикле событий asyncio и возвращает результат.

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

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

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

Если *debug* равен `True`, цикл событий будет работать в режиме отладки. `False` явно отключает режим отладки. `None` используется для соблюдения глобальных настроек [режима отладки](https://python-all.ru/3.14/library/asyncio-dev.html#asyncio-debug-mode).

Если *loop\_factory* не равен `None`, то он используется для создания нового цикла событий; в противном случае используется [`asyncio.new_event_loop()`](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio.new_event_loop). В конце цикл закрывается. Эту функцию следует использовать как главную точку входа в asyncio-программы, и в идеале она должна быть вызвана только один раз. Рекомендуется использовать *loop\_factory* для настройки цикла событий вместо политик. Передача [`asyncio.EventLoop`](https://python-all.ru/3.14/library/asyncio-eventloop.html#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()`](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio.loop.shutdown_default_executor).

Изменено в версии 3.10: *debug* по умолчанию равен `None`, чтобы соблюдать глобальные настройки режима отладки.

Изменено в версии 3.12: Добавлен параметр *loop\_factory*.

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

> **Примечание**
>
> Система политик `asyncio` устарела и будет удалена в Python 3.16; начиная с этой версии, для настройки цикла событий нужен явный *loop\_factory*.

## [Контекстный менеджер Runner](https://python-all.ru/3.14/library/asyncio-runner.html#id2)

#### `class asyncio.Runner(*, debug=None, loop_factory=None)`

Контекстный менеджер, упрощающий *множественные* вызовы асинхронных функций в одном контексте.

Иногда несколько асинхронных функций верхнего уровня нужно вызывать в одном [цикле событий](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio-event-loop) и [`contextvars.Context`](https://python-all.ru/3.14/library/contextvars.html#contextvars.Context).

Если *debug* равен `True`, цикл событий будет работать в режиме отладки. `False` явно отключает режим отладки. `None` используется для соблюдения глобальных настроек [режима отладки](https://python-all.ru/3.14/library/asyncio-dev.html#asyncio-debug-mode).

*loop\_factory* может использоваться для переопределения создания цикла. Ответственность *loop\_factory* – установить созданный цикл как текущий. По умолчанию используется [`asyncio.new_event_loop()`](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio.new_event_loop) и устанавливается как текущий цикл событий с помощью [`asyncio.set_event_loop()`](https://python-all.ru/3.14/library/asyncio-eventloop.html#asyncio.set_event_loop), если *loop\_factory* равен `None`.

В принципе, пример [`asyncio.run()`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.run) можно переписать с использованием runner:

```python
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`](https://python-all.ru/3.14/library/contextvars.html#contextvars.Context) для выполнения кода. Если context равен `None`, используется контекст runner по умолчанию.

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

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

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

#### `close()`

Закрывает runner.

Завершает асинхронные генераторы, останавливает исполнитель по умолчанию, закрывает цикл событий и освобождает встроенный [`contextvars.Context`](https://python-all.ru/3.14/library/contextvars.html#contextvars.Context).

#### `get_loop()`

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

> **Примечание**
>
> `Runner` использует стратегию ленивой инициализации: его конструктор не инициализирует нижележащие низкоуровневые структуры.
>
> Встроенные *цикл событий* и *контекст* создаются при входе в тело [`with`](https://python-all.ru/3.14/reference/compound_stmts.html#with) или при первом вызове [`run()`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.run) или [`get_loop()`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.Runner.get_loop).

## [Обработка прерывания с клавиатуры](https://python-all.ru/3.14/library/asyncio-runner.html#id3)

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

Когда [`signal.SIGINT`](https://python-all.ru/3.14/library/signal.html#signal.SIGINT) возбуждается `Ctrl`-`C`, по умолчанию в главном потоке возбуждается исключение [`KeyboardInterrupt`](https://python-all.ru/3.14/library/exceptions.html#KeyboardInterrupt). Однако это не работает с [`asyncio`](https://python-all.ru/3.14/library/asyncio.html#module-asyncio), поскольку оно может прервать внутренние механизмы asyncio и привести к зависанию программы при завершении.

Чтобы смягчить эту проблему, [`asyncio`](https://python-all.ru/3.14/library/asyncio.html#module-asyncio) обрабатывает [`signal.SIGINT`](https://python-all.ru/3.14/library/signal.html#signal.SIGINT) следующим образом:

1. [`asyncio.Runner.run()`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.Runner.run) устанавливает собственный обработчик [`signal.SIGINT`](https://python-all.ru/3.14/library/signal.html#signal.SIGINT) до выполнения любого пользовательского кода и удаляет его при выходе из функции.
2. [`Runner`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.Runner) создаёт главную задачу для переданной корутины для её выполнения.
3. Когда [`signal.SIGINT`](https://python-all.ru/3.14/library/signal.html#signal.SIGINT) возбуждается `Ctrl`-`C`, пользовательский обработчик сигнала отменяет главную задачу вызовом [`asyncio.Task.cancel()`](https://python-all.ru/3.14/library/asyncio-task.html#asyncio.Task.cancel), что возбуждает [`asyncio.CancelledError`](https://python-all.ru/3.14/library/asyncio-exceptions.html#asyncio.CancelledError) внутри главной задачи. Это приводит к разворачиванию стека Python, блоки `try/except` и `try/finally` можно использовать для очистки ресурсов. После отмены главной задачи [`asyncio.Runner.run()`](https://python-all.ru/3.14/library/asyncio-runner.html#asyncio.Runner.run) возбуждает [`KeyboardInterrupt`](https://python-all.ru/3.14/library/exceptions.html#KeyboardInterrupt).
4. Пользователь может написать плотный цикл, который не может быть прерван с помощью [`asyncio.Task.cancel()`](https://python-all.ru/3.14/library/asyncio-task.html#asyncio.Task.cancel); в этом случае второе нажатие `Ctrl`-`C` немедленно возбуждает [`KeyboardInterrupt`](https://python-all.ru/3.14/library/exceptions.html#KeyboardInterrupt) без отмены главной задачи.
