策略 — Python 文档

来自菜鸟教程
Python/docs/3.10/library/asyncio-policy
跳转至:导航、​搜索

政策

事件循环策略是一个全局的每个进程对象,用于控制事件循环的管理。 每个事件循环都有一个默认策略,可以使用策略 API 更改和自定义。

策略定义了 context 的概念,并为每个上下文管理一个单独的事件循环。 默认策略将 context 定义为当前线程。

通过使用自定义事件循环策略,可以自定义 get_event_loop()set_event_loop()new_event_loop() 函数的行为。

策略对象应实现 AbstractEventLoopPolicy 抽象基类中定义的 API。

获取和设置策略

以下函数可用于获取和设置当前进程的策略:

asyncio.get_event_loop_policy()
返回当前进程范围的策略。
asyncio.set_event_loop_policy(policy)

将当前进程范围的策略设置为 policy

如果policy设置为None,则恢复默认策略。


策略对象

抽象事件循环策略基类定义如下:

class asyncio.AbstractEventLoopPolicy

异步策略的抽象基类。

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

默认的异步策略。 在 Unix 上使用 SelectorEventLoop,在 Windows 上使用 ProactorEventLoop

无需手动安装默认策略。 asyncio 配置为自动使用默认策略。

3.8 版更改: 在 Windows 上,现在默认使用 ProactorEventLoop

class asyncio.WindowsSelectorEventLoopPolicy
使用 SelectorEventLoop 事件循环实现的替代事件循环策略。
class asyncio.WindowsProactorEventLoopPolicy
使用 ProactorEventLoop 事件循环实现的替代事件循环策略。


进程观察者

进程观察器允许自定义事件循环如何监视 Unix 上的子进程。 具体来说,事件循环需要知道子进程何时退出。

在 asyncio 中,子进程是使用 create_subprocess_exec()loop.subprocess_exec() 函数创建的。

asyncio 定义了AbstractChildWatcher抽象基类,子观察者应该实现,有四种不同的实现:ThreadedChildWatcher(配置为默认使用),MultiLoopChildWatcherSafeChildWatcherFastChildWatcher

另请参阅 子进程和线程 部分。

以下两个函数可用于自定义 asyncio 事件循环使用的子进程观察器实现:

asyncio.get_child_watcher()
返回当前策略的当前子观察者。
asyncio.set_child_watcher(watcher)
对于当前策略,将当前子观察者设置为 watcherwatcher 必须实现在 AbstractChildWatcher 基类中定义的方法。

笔记

第三方事件循环实现可能不支持自定义子观察者。 对于此类事件循环,使用 set_child_watcher() 可能被禁止或无效。


class asyncio.AbstractChildWatcher
add_child_handler(pid, callback, *args)

注册一个新的子处理程序。

当PID等于pid的进程终止时,安排调用callback(pid, returncode, *args)。 为同一进程指定另一个回调会替换之前的处理程序。

callback callable 必须是线程安全的。

remove_child_handler(pid)

删除 PID 等于 pid 的进程的处理程序。

如果处理程序成功删除,该函数返回 True,如果没有要删除的内容,则返回 False

attach_loop(loop)

将观察者附加到事件循环。

如果观察者先前附加到事件循环,则在附加到新循环之前首先将其分离。

注意:loop 可能是 None

is_active()

如果观察者准备好使用,则返回 True

生成具有 inactive 当前子观察者的子进程会引发 RuntimeError

3.8 版中的新功能。

close()

关闭观察者。

必须调用此方法以确保清理底层资源。

class asyncio.ThreadedChildWatcher

此实现为每个子进程生成启动一个新的等待线程。

即使 asyncio 事件循环在非主操作系统线程中运行,它也能可靠地工作。

处理大量子进程时没有明显的开销(每次子进程终止时 O(1)),但是每个进程启动一个线程需要额外的内存。

默认情况下使用此观察器。

3.8 版中的新功能。

class asyncio.MultiLoopChildWatcher

此实现在实例化时注册 SIGCHLD 信号处理程序。 这可能会破坏为 SIGCHLD 信号安装自定义处理程序的第三方代码。

观察者通过在 SIGCHLD 信号上显式轮询每个进程来避免中断其他代码生成进程。

一旦安装了观察者,从不同线程运行子进程就没有限制。

该解决方案是安全的,但在处理大量进程(每次收到 SIGCHLDO(n))时会产生大量开销。

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 是一个“Goldilocks”子观察器实现。 它不需要信号或线程,不会干扰在事件循环之外启动的任何进程,并且随着事件循环启动的子进程的数量线性扩展。 主要缺点是 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())