Документация Python неофициальный перевод
Содержание страницы

ПолитикиPolicies

Политика цикла событий – это глобальный для каждого процесса объект, управляющий циклом событий. Каждый цикл событий имеет политику по умолчанию, которую можно изменить и настроить с помощью API политик.

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

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

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())