> **Источник:** https://python-all.ru/3.11/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.11/Lib/asyncio/runners.py)

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

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

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

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

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

Выполняет [корутину](https://python-all.ru/3.11/glossary.html#term-coroutine) *coro* и возвращает результат.

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

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

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

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

Пример:

```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.11/library/asyncio-eventloop.html#asyncio.loop.shutdown_default_executor).

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

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

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

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

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

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

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

В принципе, пример [`asyncio.run()`](https://python-all.ru/3.11/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.11.

#### `run(coro, *, context=None)`

Запускает [корутину](https://python-all.ru/3.11/glossary.html#term-coroutine) *coro* во встроенном цикле событий.

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

Необязательный аргумент *context* (только по ключу) позволяет указать пользовательский [`contextvars.Context`](https://python-all.ru/3.11/library/contextvars.html#contextvars.Context) для выполнения *coro*. Если `None`, используется контекст запускатора по умолчанию.

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

#### `close()`

Закрывает runner.

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

#### `get_loop()`

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

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

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

Новое в версии 3.11.

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

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

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