Содержание страницы
Политики¶Policies
Политика цикла событий – это глобальный объект, используемый для получения и установки текущего цикла событий, а также для создания новых циклов событий. Стандартную политику можно заменить на встроенные альтернативы для использования других реализаций цикла событий или заменить пользовательской политикой, которая может переопределять это поведение.
Объект политики получает и устанавливает отдельный цикл событий для каждого контекста. По умолчанию это выполняется для каждого потока, хотя пользовательские политики могут определять контекст иначе.
Пользовательские политики цикла событий могут управлять поведением
get_event_loop(), set_event_loop() и new_event_loop().
Объекты политик должны реализовывать API, определённые
в абстрактном базовом классе AbstractEventLoopPolicy.
Получение и установка политики¶Getting and Setting the Policy
Следующие функции можно использовать для получения и установки политики для текущего процесса:
-
asyncio.get_event_loop_policy()¶ Возвращает текущую политику для всего процесса.
-
asyncio.set_event_loop_policy(policy)¶ Устанавливает текущую политику для всего процесса в policy.
Если для policy установлено значение
None, восстанавливается стандартная политика.
Объекты политик¶Policy Objects
Абстрактный базовый класс политики цикла событий определяется следующим образом:
-
class
asyncio.AbstractEventLoopPolicy¶ Абстрактный базовый класс для политик asyncio.
-
get_event_loop()¶ Возвращает цикл событий для текущего контекста.
Возвращает объект цикла событий, реализующий интерфейс
AbstractEventLoop.Этот метод никогда не должен возвращать
None.Изменено в версии 3.6.
-
set_event_loop(loop)¶ Устанавливает цикл событий для текущего контекста равным loop.
-
new_event_loop()¶ Создаёт и возвращает новый объект цикла событий.
Этот метод никогда не должен возвращать
None.
-
get_child_watcher()¶ Получить объект наблюдателя за дочерними процессами.
Возвращает объект наблюдателя, реализующий
AbstractChildWatcherинтерфейс.Эта функция специфична для Unix.
-
set_child_watcher(watcher)¶ Устанавливает текущий наблюдатель за дочерними процессами на watcher.
Эта функция специфична для Unix.
-
asyncio включает следующие встроенные политики:
-
class
asyncio.DefaultEventLoopPolicy¶ Политика asyncio по умолчанию. Использует
SelectorEventLoopв Unix иProactorEventLoopв Windows.Нет необходимости устанавливать политику по умолчанию вручную. asyncio настроена на автоматическое использование политики по умолчанию.
Изменено в версии 3.8: В Windows
ProactorEventLoopтеперь используется по умолчанию.Примечание
В Python версий 3.10.9, 3.11.1 и 3.12 метод
get_event_loop()политики asyncio по умолчанию генерируетDeprecationWarning, если не выполняется ни один цикл событий и не установлен текущий цикл. В одной из будущих версий Python это станет ошибкой.
-
class
asyncio.WindowsSelectorEventLoopPolicy¶ Альтернативная политика цикла событий, использующая реализацию цикла событий
SelectorEventLoop.Доступность: Windows.
-
class
asyncio.WindowsProactorEventLoopPolicy¶ Альтернативная политика цикла событий, использующая реализацию цикла событий
ProactorEventLoop.Доступность: Windows.
Наблюдатели за процессами¶Process Watchers
Наблюдатель за процессами позволяет настраивать, как цикл событий отслеживает дочерние процессы в Unix. В частности, циклу событий необходимо знать, когда дочерний процесс завершился.
В asyncio дочерние процессы создаются с помощью функций
create_subprocess_exec() и loop.subprocess_exec().
asyncio определяет абстрактный базовый класс AbstractChildWatcher, который должны реализовывать наблюдатели за дочерними процессами, и имеет четыре реализации:
ThreadedChildWatcher (используется по умолчанию),
MultiLoopChildWatcher, SafeChildWatcher и
FastChildWatcher.
См. также раздел Подпроцессы и потоки .
Следующие две функции можно использовать для настройки реализации наблюдателя за дочерними процессами, используемого циклом событий asyncio:
-
asyncio.get_child_watcher()¶ Возвращает текущий наблюдатель за дочерними процессами для текущей политики.
-
asyncio.set_child_watcher(watcher)¶ Устанавливает текущий наблюдатель за дочерними процессами на watcher для текущей политики. watcher должен реализовывать методы, определённые в базовом классе
AbstractChildWatcher.
Примечание
Реализации циклов событий от сторонних разработчиков могут не поддерживать пользовательские наблюдатели за дочерними процессами. Для таких циклов событий использование
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.Новое в версии 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).Наблюдатель не нарушает работу другого кода, запускающего процессы, благодаря явному опросу каждого процесса при получении сигнала
SIGCHLD.Это решение так же безопасно, как
MultiLoopChildWatcher, и имеет ту же сложность O(N), но для работы требует работающего цикла событий в главном потоке.
-
class
asyncio.FastChildWatcher¶ Эта реализация собирает каждый завершённый процесс, напрямую вызывая
os.waitpid(-1), что потенциально нарушает работу другого кода, запускающего процессы и ожидающего их завершения.Нет заметных накладных расходов при обработке большого количества дочерних процессов (O(1) каждый раз при завершении дочернего процесса).
Это решение требует работающего цикла событий в главном потоке, как и
SafeChildWatcher.
-
class
asyncio.PidfdChildWatcher¶ Данная реализация опрашивает файловые дескрипторы процессов (pidfds) для ожидания завершения дочернего процесса. В некотором смысле
PidfdChildWatcher– это реализация наблюдателя за дочерними процессами «Златовласка». Она не требует сигналов или потоков, не мешает процессам, запущенным вне цикла событий, и масштабируется линейно от количества подпроцессов, запущенных циклом событий. Основной недостаток в том, что pidfds специфичны для Linux и работают только на современных (5.3+) ядрах.Новое в версии 3.9.
Пользовательские политики¶Custom Policies
Для реализации новой политики цикла событий рекомендуется создать подкласс
DefaultEventLoopPolicy и переопределить методы, для которых
требуется особое поведение, например:
class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
def get_event_loop(self):
"""Получить цикл событий.
Это может быть None или экземпляр EventLoop.
"""
loop = super().get_event_loop()
# Сделать что-то с циклом ...
return loop
asyncio.set_event_loop_policy(MyEventLoopPolicy())