asyncio-policy.md
1> **Источник:** https://python-all.ru/3.10/library/asyncio-policy.html2>3> «Документация Python на русском» – неофициальный перевод официальной документации Python: версии от 2.6 до 3.16, полнотекстовый поиск, английский оригинал рядом с переводом. Эта Markdown-версия страницы предназначена для работы с LLM: вставьте её в ChatGPT, Claude или Cursor.45---67# Политики89Политика цикла событий – это глобальный объект, используемый для получения и установки текущего [цикла событий](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), которая может переопределять это поведение.1011Объект [политики](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio-policy-objects) получает и устанавливает отдельный цикл событий для каждого *контекста*. По умолчанию это выполняется для каждого потока, хотя пользовательские политики могут определять *контекст* иначе.1213Пользовательские политики цикла событий могут управлять поведением [`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).1415Объекты политик должны реализовывать API, определённые в абстрактном базовом классе [`AbstractEventLoopPolicy`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractEventLoopPolicy).1617## Получение и установка политики1819Следующие функции можно использовать для получения и установки политики для текущего процесса:2021#### `asyncio.get_event_loop_policy()`2223Возвращает текущую политику для всего процесса.2425#### `asyncio.set_event_loop_policy(policy)`2627Устанавливает текущую политику для всего процесса в *policy*.2829Если для *policy* установлено значение `None`, восстанавливается стандартная политика.3031## Объекты политик3233Абстрактный базовый класс политики цикла событий определяется следующим образом:3435#### `class asyncio.AbstractEventLoopPolicy`3637Абстрактный базовый класс для политик asyncio.3839#### `get_event_loop()`4041Возвращает цикл событий для текущего контекста.4243Возвращает объект цикла событий, реализующий интерфейс [`AbstractEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.AbstractEventLoop).4445Этот метод никогда не должен возвращать `None`.4647Изменено в версии 3.6.4849#### `set_event_loop(loop)`5051Устанавливает цикл событий для текущего контекста равным *loop*.5253#### `new_event_loop()`5455Создаёт и возвращает новый объект цикла событий.5657Этот метод никогда не должен возвращать `None`.5859#### `get_child_watcher()`6061Получить объект наблюдателя за дочерними процессами.6263Возвращает объект наблюдателя, реализующий [`AbstractChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractChildWatcher) интерфейс.6465Эта функция специфична для Unix.6667#### `set_child_watcher(watcher)`6869Устанавливает текущий наблюдатель за дочерними процессами на *watcher*.7071Эта функция специфична для Unix.7273asyncio включает следующие встроенные политики:7475#### `class asyncio.DefaultEventLoopPolicy`7677Политика 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.7879Нет необходимости устанавливать политику по умолчанию вручную. asyncio настроена на автоматическое использование политики по умолчанию.8081Изменено в версии 3.8: В Windows [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop) теперь используется по умолчанию.8283> **Примечание**84>85> В 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 это станет ошибкой.8687#### `class asyncio.WindowsSelectorEventLoopPolicy`8889Альтернативная политика цикла событий, использующая реализацию цикла событий [`SelectorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.SelectorEventLoop).9091[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Windows.9293#### `class asyncio.WindowsProactorEventLoopPolicy`9495Альтернативная политика цикла событий, использующая реализацию цикла событий [`ProactorEventLoop`](https://python-all.ru/3.10/library/asyncio-eventloop.html#asyncio.ProactorEventLoop).9697[Доступность](https://python-all.ru/3.10/library/intro.html#availability): Windows.9899## Наблюдатели за процессами100101Наблюдатель за процессами позволяет настраивать, как цикл событий отслеживает дочерние процессы в Unix. В частности, циклу событий необходимо знать, когда дочерний процесс завершился.102103В 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).104105asyncio определяет абстрактный базовый класс [`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).106107См. также раздел [Подпроцессы и потоки](https://python-all.ru/3.10/library/asyncio-subprocess.html#asyncio-subprocess-threads) .108109Следующие две функции можно использовать для настройки реализации наблюдателя за дочерними процессами, используемого циклом событий asyncio:110111#### `asyncio.get_child_watcher()`112113Возвращает текущий наблюдатель за дочерними процессами для текущей политики.114115#### `asyncio.set_child_watcher(watcher)`116117Устанавливает текущий наблюдатель за дочерними процессами на *watcher* для текущей политики. *watcher* должен реализовывать методы, определённые в базовом классе [`AbstractChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.AbstractChildWatcher).118119> **Примечание**120>121> Реализации циклов событий от сторонних разработчиков могут не поддерживать пользовательские наблюдатели за дочерними процессами. Для таких циклов событий использование [`set_child_watcher()`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.set_child_watcher) может быть запрещено или не иметь эффекта.122123#### `class asyncio.AbstractChildWatcher`124125#### `add_child_handler(pid, callback, *args)`126127Регистрирует новый обработчик дочернего процесса.128129Организует вызов `callback(pid, returncode, *args)` при завершении процесса с PID, равным *pid*. Указание другого колбэка для того же процесса заменяет предыдущий обработчик.130131Вызываемый объект *колбэк* должен быть потокобезопасным.132133#### `remove_child_handler(pid)`134135Удаляет обработчик для процесса с PID, равным *pid*.136137Функция возвращает `True`, если обработчик был успешно удалён, и `False`, если удалять было нечего.138139#### `attach_loop(loop)`140141Присоединяет наблюдатель к циклу событий.142143Если наблюдатель ранее был присоединён к циклу событий, то перед присоединением к новому циклу он сначала отсоединяется.144145Примечание: loop может быть `None`.146147#### `is_active()`148149Возвращает `True`, если наблюдатель готов к использованию.150151Запуск подпроцесса с *неактивным* текущим наблюдателем дочерних процессов вызывает [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError).152153Новое в версии 3.8.154155#### `close()`156157Закрывает наблюдатель.158159Этот метод необходимо вызвать, чтобы гарантировать очистку нижележащих ресурсов.160161#### `class asyncio.ThreadedChildWatcher`162163Эта реализация запускает новый ожидающий поток для каждого запущенного подпроцесса.164165Она работает надёжно, даже если цикл событий asyncio выполняется не в главном потоке ОС.166167Нет заметных накладных расходов при обработке большого количества дочерних процессов (*O(1)* каждый раз при завершении дочернего процесса), но запуск потока на каждый процесс требует дополнительной памяти.168169Этот наблюдатель используется по умолчанию.170171Новое в версии 3.8.172173#### `class asyncio.MultiLoopChildWatcher`174175Эта реализация регистрирует обработчик сигнала `SIGCHLD` при создании экземпляра. Это может нарушить работу стороннего кода, который устанавливает собственный обработчик сигнала `SIGCHLD`.176177Наблюдатель не нарушает работу другого кода, запускающего процессы, благодаря явному опросу каждого процесса при получении сигнала `SIGCHLD`.178179После установки наблюдателя нет ограничений на запуск подпроцессов из разных потоков.180181Решение безопасно, но имеет значительные накладные расходы при обработке большого количества процессов (*O(n)* каждый раз при получении `SIGCHLD`).182183Новое в версии 3.8.184185#### `class asyncio.SafeChildWatcher`186187Эта реализация использует активный цикл событий из главного потока для обработки сигнала `SIGCHLD`. Если в главном потоке нет работающего цикла событий, другой поток не может запустить подпроцесс (возникает [`RuntimeError`](https://python-all.ru/3.10/library/exceptions.html#RuntimeError)).188189Наблюдатель не нарушает работу другого кода, запускающего процессы, благодаря явному опросу каждого процесса при получении сигнала `SIGCHLD`.190191Это решение так же безопасно, как [`MultiLoopChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.MultiLoopChildWatcher), и имеет ту же сложность *O(N)*, но для работы требует работающего цикла событий в главном потоке.192193#### `class asyncio.FastChildWatcher`194195Эта реализация собирает каждый завершённый процесс, напрямую вызывая `os.waitpid(-1)`, что потенциально нарушает работу другого кода, запускающего процессы и ожидающего их завершения.196197Нет заметных накладных расходов при обработке большого количества дочерних процессов (*O(1)* каждый раз при завершении дочернего процесса).198199Это решение требует работающего цикла событий в главном потоке, как и [`SafeChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.SafeChildWatcher).200201#### `class asyncio.PidfdChildWatcher`202203Данная реализация опрашивает файловые дескрипторы процессов (pidfds) для ожидания завершения дочернего процесса. В некотором смысле [`PidfdChildWatcher`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.PidfdChildWatcher) – это реализация наблюдателя за дочерними процессами «Златовласка». Она не требует сигналов или потоков, не мешает процессам, запущенным вне цикла событий, и масштабируется линейно от количества подпроцессов, запущенных циклом событий. Основной недостаток в том, что pidfds специфичны для Linux и работают только на современных (5.3+) ядрах.204205Новое в версии 3.9.206207## Пользовательские политики208209Для реализации новой политики цикла событий рекомендуется создать подкласс [`DefaultEventLoopPolicy`](https://python-all.ru/3.10/library/asyncio-policy.html#asyncio.DefaultEventLoopPolicy) и переопределить методы, для которых требуется особое поведение, например:210211```python212class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):213214 def get_event_loop(self):215 """Получить цикл событий.216217 Это может быть None или экземпляр EventLoop.218 """219 loop = super().get_event_loop()220 # Сделать что-то с циклом ...221 return loop222223asyncio.set_event_loop_policy(MyEventLoopPolicy())224```225