Политика¶
Политика цикла событий - это глобальный объект для каждого процесса, который контролирует управление циклом событий. Каждый цикл событий имеет политику по умолчанию, которую можно изменить и настроить с помощью API политики.
Политика определяет понятие контекста и управляет отдельным циклом событий для каждого контекста. Политика по умолчанию определяет контекст как текущий поток.
Используя пользовательскую политику цикла событий, можно настроить поведение функций get_event_loop()
, set_event_loop()
и new_event_loop()
.
Объекты политики должны реализовывать API, определенные в абстрактном базовом классе AbstractEventLoopPolicy
.
Получение и настройка политики¶
Следующие функции можно использовать для получения и установки политики для текущего процесса:
-
asyncio.
get_event_loop_policy
()¶ Вернуть текущую политику в рамках всего процесса.
-
asyncio.
set_event_loop_policy
(policy)¶ Установите текущую политику всего процесса на policy.
Если policy имеет значение
None
, восстанавливается политика по умолчанию.
Объекты политики¶
Абстрактный базовый класс политики циклов событий определяется следующим образом:
-
class
asyncio.
AbstractEventLoopPolicy
¶ Абстрактный базовый класс для политик asyncio.
-
get_event_loop
()¶ Получение цикла событий для текущего контекста.
Возвращает объект цикла событий, реализующий интерфейс
AbstractEventLoop
.Этот метод никогда не должен возвращать
None
.Изменено в версии 3.6.
-
set_event_loop
(loop)¶ Установите цикл событий для текущего контекста на loop.
-
new_event_loop
()¶ Создает и возвращает новый объект цикла событий.
Этот метод никогда не должен возвращать
None
.
-
get_child_watcher
()¶ Получение объекта наблюдателя дочернего процесса.
Возвращает объект watcher, реализующий интерфейс
AbstractChildWatcher
.Эта функция специфична для Unix.
-
set_child_watcher
(watcher)¶ Установите текущий наблюдатель дочернего процесса в watcher.
Эта функция специфична для Unix.
-
asyncio поставляется со следующими встроенными политиками:
-
class
asyncio.
DefaultEventLoopPolicy
¶ Политика asyncio по умолчанию. Используется
SelectorEventLoop
на Unix иProactorEventLoop
на Windows.Нет необходимости устанавливать политику по умолчанию вручную. asyncio настроен на автоматическое использование политики по умолчанию.
Изменено в версии 3.8: В Windows по умолчанию теперь используется
ProactorEventLoop
.
-
class
asyncio.
WindowsSelectorEventLoopPolicy
¶ Альтернативная политика цикла событий, использующая реализацию цикла событий
SelectorEventLoop
.Availability: Windows.
-
class
asyncio.
WindowsProactorEventLoopPolicy
¶ Альтернативная политика цикла событий, использующая реализацию цикла событий
ProactorEventLoop
.Availability: Windows.
Наблюдатели за процессом¶
Наблюдатель процесса позволяет настраивать то, как цикл событий отслеживает дочерние процессы в Unix. В частности, цикл событий должен знать, когда дочерний процесс завершился.
В asyncio дочерние процессы создаются с помощью функций create_subprocess_exec()
и loop.subprocess_exec()
.
asyncio определяет абстрактный базовый класс AbstractChildWatcher
, который должны реализовывать дочерние наблюдатели, и имеет четыре различных реализации: ThreadedChildWatcher
(настроен на использование по умолчанию), MultiLoopChildWatcher
, SafeChildWatcher
и FastChildWatcher
.
См. также раздел Subprocess and Threads.
Следующие две функции могут быть использованы для настройки реализации наблюдателя дочернего процесса, используемого циклом событий 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. Указание другого обратного вызова для того же процесса заменяет предыдущий обработчик.Вызываемый callback должен быть потокобезопасным.
-
remove_child_handler
(pid)¶ Удаляет обработчик для процесса с PID, равным pid.
Функция возвращает
True
, если обработчик был успешно удален,False
, если удалять было нечего.
-
attach_loop
(loop)¶ Прикрепите наблюдателя к циклу событий.
Если наблюдатель был ранее присоединен к циклу событий, то он сначала отсоединяется перед присоединением к новому циклу.
Примечание: цикл может быть
None
.
-
is_active
()¶ Возвращает
True
, если наблюдатель готов к использованию.Порождение подпроцесса с неактивным текущим дочерним наблюдателем приводит к появлению
RuntimeError
.Добавлено в версии 3.8.
-
close
()¶ Закройте наблюдателя.
Этот метод должен быть вызван, чтобы убедиться, что базовые ресурсы очищены.
-
-
class
asyncio.
ThreadedChildWatcher
¶ Эта реализация запускает новый поток ожидания для каждого порождения подпроцесса.
Он надежно работает, даже когда цикл событий asyncio выполняется не в главном потоке ОС.
При обработке большого числа дочерних процессов заметных накладных расходов нет (O(1) при каждом завершении дочернего процесса), но запуск потока на процесс требует дополнительной памяти.
Этот наблюдатель используется по умолчанию.
Добавлено в версии 3.8.
-
class
asyncio.
MultiLoopChildWatcher
¶ Эта реализация регистрирует обработчик сигнала
SIGCHLD
при инстанцировании. Это может нарушить сторонний код, который устанавливает собственный обработчик для сигналаSIGCHLD
.Эта реализация регистрирует обработчик сигнала
SIGCHLD
при инстанцировании. Это может нарушить сторонний код, который устанавливает собственный обработчик для сигнала :py .Наблюдатель позволяет избежать прерывания других процессов, порождающих код, путем явного опроса каждого процесса по сигналу :py .
Решение безопасно, но имеет значительные накладные расходы при обработке большого количества процессов (O(n) при каждом получении
SIGCHLD
).Добавлено в версии 3.8.
-
class
asyncio.
SafeChildWatcher
¶ Эта реализация использует активный цикл событий из главного потока для обработки сигнала
SIGCHLD
. Если в главном потоке не запущен цикл событий, то другой поток не может породить подпроцесс (возникает сигналRuntimeError
).Эта реализация регистрирует обработчик сигнала
SIGCHLD
при инстанцировании. Это может нарушить сторонний код, который устанавливает собственный обработчик для сигнала :py .Это решение так же безопасно, как
MultiLoopChildWatcher
, и имеет ту же O(N) сложность, но для его работы требуется запущенный цикл событий в главном потоке.
-
class
asyncio.
FastChildWatcher
¶ Эта реализация получает все завершенные процессы, вызывая
os.waitpid(-1)
напрямую, возможно, нарушая другой код, порождающий процессы и ожидающий их завершения.При обработке большого количества дочерних программ нет заметных накладных расходов (O(1) при каждом завершении дочерней программы).
Для работы этого решения требуется запущенный цикл событий в главном потоке, как
SafeChildWatcher
.
-
class
asyncio.
PidfdChildWatcher
¶ Эта реализация опрашивает дескрипторы файлов процессов (pidfds), чтобы ожидать завершения дочернего процесса. В некоторых отношениях
PidfdChildWatcher
является «златовласой» реализацией наблюдателя за дочерними процессами. Она не требует сигналов или потоков, не вмешивается в процессы, запущенные вне цикла событий, и линейно масштабируется с количеством подпроцессов, запущенных циклом событий. Основной недостаток заключается в том, что pidfds специфичен для Linux и работает только на последних (5.3+) ядрах.Добавлено в версии 3.9.
Пользовательские политики¶
Чтобы реализовать новую политику цикла событий, рекомендуется подкласс DefaultEventLoopPolicy
и переопределить методы, для которых требуется пользовательское поведение, например:
class MyEventLoopPolicy(asyncio.DefaultEventLoopPolicy):
def get_event_loop(self):
"""Get the event loop.
This may be None or an instance of EventLoop.
"""
loop = super().get_event_loop()
# Do something with loop ...
return loop
asyncio.set_event_loop_policy(MyEventLoopPolicy())