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

---

# Политики

Политика цикла событий – это глобальный объект, используемый для получения и установки текущего [цикла событий](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio-event-loop), а также для создания новых циклов событий. Стандартную политику можно [заменить](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-policy-get-set) на [встроенные альтернативы](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-policy-builtin) для использования других реализаций цикла событий или заменить [пользовательской политикой](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-custom-policies), которая может переопределять это поведение.

Объект [политики](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-policy-objects) получает и устанавливает отдельный цикл событий для каждого *контекста*. По умолчанию это выполняется для каждого потока, хотя пользовательские политики могут определять *контекст* иначе.

Пользовательские политики цикла событий могут управлять поведением [`get_event_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop), [`set_event_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.set_event_loop) и [`new_event_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.new_event_loop).

Объекты политик должны реализовывать API, определённые в абстрактном базовом классе [`AbstractEventLoopPolicy`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractEventLoopPolicy).

## Получение и установка политики

Следующие функции можно использовать для получения и установки политики для текущего процесса:

#### `asyncio.get_event_loop_policy()`

Возвращает текущую политику для всего процесса.

#### `asyncio.set_event_loop_policy(policy)`

Устанавливает текущую политику для всего процесса в *policy*.

Если для *policy* установлено значение `None`, восстанавливается стандартная политика.

## Объекты политик

Абстрактный базовый класс политики цикла событий определяется следующим образом:

#### `class asyncio.AbstractEventLoopPolicy`

Абстрактный базовый класс для политик asyncio.

#### `get_event_loop()`

Возвращает цикл событий для текущего контекста.

Возвращает объект цикла событий, реализующий интерфейс [`AbstractEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.AbstractEventLoop).

Этот метод никогда не должен возвращать `None`.

Изменено в версии 3.6.

#### `set_event_loop(loop)`

Устанавливает цикл событий для текущего контекста равным *loop*.

#### `new_event_loop()`

Создаёт и возвращает новый объект цикла событий.

Этот метод никогда не должен возвращать `None`.

#### `get_child_watcher()`

Получить объект наблюдателя за дочерними процессами.

Возвращает объект наблюдателя, реализующий [`AbstractChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractChildWatcher) интерфейс.

Эта функция специфична для Unix.

#### `set_child_watcher(watcher)`

Устанавливает текущий наблюдатель за дочерними процессами на *watcher*.

Эта функция специфична для Unix.

asyncio включает следующие встроенные политики:

#### `class asyncio.DefaultEventLoopPolicy`

Политика asyncio по умолчанию. Использует [`SelectorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.SelectorEventLoop) в Unix и [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) в Windows.

Нет необходимости устанавливать политику по умолчанию вручную. asyncio настроена на автоматическое использование политики по умолчанию.

Изменено в версии 3.8: В Windows [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) теперь используется по умолчанию.

> **Примечание**
>
> В Python версий 3.10.9, 3.11.1 и 3.12 метод [`get_event_loop()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.get_event_loop) политики asyncio по умолчанию генерирует [`DeprecationWarning`](https://python-all.ru/3.10/library/exceptions.html#DeprecationWarning), если не выполняется ни один цикл событий и не установлен текущий цикл. В одной из будущих версий Python это станет ошибкой.

#### `class asyncio.WindowsSelectorEventLoopPolicy`

Альтернативная политика цикла событий, использующая реализацию цикла событий [`SelectorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.SelectorEventLoop).

[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Windows.

#### `class asyncio.WindowsProactorEventLoopPolicy`

Альтернативная политика цикла событий, использующая реализацию цикла событий [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop).

[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Windows.

## Наблюдатели за процессами

Наблюдатель за процессами позволяет настраивать, как цикл событий отслеживает дочерние процессы в Unix. В частности, циклу событий необходимо знать, когда дочерний процесс завершился.

В asyncio дочерние процессы создаются с помощью функций [`create_subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio.create_subprocess_exec) и [`loop.subprocess_exec()`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.loop.subprocess_exec).

asyncio определяет абстрактный базовый класс [`AbstractChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractChildWatcher), который должны реализовывать наблюдатели за дочерними процессами, и имеет четыре реализации: [`ThreadedChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.ThreadedChildWatcher) (используется по умолчанию), [`MultiLoopChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.MultiLoopChildWatcher), [`SafeChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.SafeChildWatcher) и [`FastChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.FastChildWatcher).

См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio-subprocess-threads) .

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

#### `asyncio.get_child_watcher()`

Возвращает текущий наблюдатель за дочерними процессами для текущей политики.

#### `asyncio.set_child_watcher(watcher)`

Устанавливает текущий наблюдатель за дочерними процессами на *watcher* для текущей политики. *watcher* должен реализовывать методы, определённые в базовом классе [`AbstractChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractChildWatcher).

> **Примечание**
>
> Реализации циклов событий от сторонних разработчиков могут не поддерживать пользовательские наблюдатели за дочерними процессами. Для таких циклов событий использование [`set_child_watcher()`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.set_child_watcher) может быть запрещено или не иметь эффекта.

#### `class asyncio.AbstractChildWatcher`

#### `add_child_handler(pid, callback, *args)`

Регистрирует новый обработчик дочернего процесса.

Организует вызов `callback(pid, returncode, *args)` при завершении процесса с PID, равным *pid*. Указание другого колбэка для того же процесса заменяет предыдущий обработчик.

Вызываемый объект *колбэк* должен быть потокобезопасным.

#### `remove_child_handler(pid)`

Удаляет обработчик для процесса с PID, равным *pid*.

Функция возвращает `True`, если обработчик был успешно удалён, и `False`, если удалять было нечего.

#### `attach_loop(loop)`

Присоединяет наблюдатель к циклу событий.

Если наблюдатель ранее был присоединён к циклу событий, то перед присоединением к новому циклу он сначала отсоединяется.

Примечание: loop может быть `None`.

#### `is_active()`

Возвращает `True`, если наблюдатель готов к использованию.

Запуск подпроцесса с *неактивным* текущим наблюдателем дочерних процессов вызывает [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError).

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

#### `close()`

Закрывает наблюдатель.

Этот метод необходимо вызвать, чтобы гарантировать очистку нижележащих ресурсов.

#### `class asyncio.ThreadedChildWatcher`

Эта реализация запускает новый ожидающий поток для каждого запущенного подпроцесса.

Она работает надёжно, даже если цикл событий asyncio выполняется не в главном потоке ОС.

Нет заметных накладных расходов при обработке большого количества дочерних процессов (*O(1)* каждый раз при завершении дочернего процесса), но запуск потока на каждый процесс требует дополнительной памяти.

Этот наблюдатель используется по умолчанию.

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

#### `class asyncio.MultiLoopChildWatcher`

Эта реализация регистрирует обработчик сигнала `SIGCHLD` при создании экземпляра. Это может нарушить работу стороннего кода, который устанавливает собственный обработчик сигнала `SIGCHLD`.

Наблюдатель не нарушает работу другого кода, запускающего процессы, благодаря явному опросу каждого процесса при получении сигнала `SIGCHLD`.

После установки наблюдателя нет ограничений на запуск подпроцессов из разных потоков.

Решение безопасно, но имеет значительные накладные расходы при обработке большого количества процессов (*O(n)* каждый раз при получении `SIGCHLD`).

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

#### `class asyncio.SafeChildWatcher`

Эта реализация использует активный цикл событий из главного потока для обработки сигнала `SIGCHLD`. Если в главном потоке нет работающего цикла событий, другой поток не может запустить подпроцесс (возникает [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError)).

Наблюдатель не нарушает работу другого кода, запускающего процессы, благодаря явному опросу каждого процесса при получении сигнала `SIGCHLD`.

Это решение так же безопасно, как [`MultiLoopChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.MultiLoopChildWatcher), и имеет ту же сложность *O(N)*, но для работы требует работающего цикла событий в главном потоке.

#### `class asyncio.FastChildWatcher`

Эта реализация собирает каждый завершённый процесс, напрямую вызывая `os.waitpid(-1)`, что потенциально нарушает работу другого кода, запускающего процессы и ожидающего их завершения.

Нет заметных накладных расходов при обработке большого количества дочерних процессов (*O(1)* каждый раз при завершении дочернего процесса).

Это решение требует работающего цикла событий в главном потоке, как и [`SafeChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.SafeChildWatcher).

#### `class asyncio.PidfdChildWatcher`

Данная реализация опрашивает файловые дескрипторы процессов (pidfds) для ожидания завершения дочернего процесса. В некотором смысле [`PidfdChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.PidfdChildWatcher) – это реализация наблюдателя за дочерними процессами «Златовласка». Она не требует сигналов или потоков, не мешает процессам, запущенным вне цикла событий, и масштабируется линейно от количества подпроцессов, запущенных циклом событий. Основной недостаток в том, что pidfds специфичны для Linux и работают только на современных (5.3+) ядрах.

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

## Пользовательские политики

Для реализации новой политики цикла событий рекомендуется создать подкласс [`DefaultEventLoopPolicy`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.DefaultEventLoopPolicy) и переопределить методы, для которых требуется особое поведение, например:

```python
class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):

    def get_event_loop(self):
        """Получить цикл событий.

        Это может быть None или экземпляр EventLoop.
        """
        loop = super().get_event_loop()
        # Сделать что-то с циклом ...
        return loop

asyncio.set_event_loop_policy(MyEventLoopPolicy())
```
