Политики

Политика событийного цикла — это глобальный объект для каждого процесса, который контролирует управление циклом событий. У каждого событийного цикла есть политика по умолчанию, которую можно изменить и настроить с помощью 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()

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

Возвращает объект-наблюдатель, реализующий интерфейс 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.

Доступность: Windows.

class asyncio.WindowsProactorEventLoopPolicy

Альтернативная политика событийного цикла, использующая реализацию событийного цикла ProactorEventLoop.

Доступность: Windows.

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

Наблюдатель за процессами позволяет настроить то, как событийный цикл отслеживает дочерние процессы в 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. Указание другого обратного вызова для того же процесса заменяет предыдущий обработчик.

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

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.

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

Для реализации новой политики событийного цикла рекомендуется создать подкласс 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())