策略 — Python 文档
政策
事件循环策略是一个全局的每个进程对象,用于控制事件循环的管理。 每个事件循环都有一个默认策略,可以使用策略 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(配置为默认使用),MultiLoopChildWatcher, SafeChildWatcher 和 FastChildWatcher。
另请参阅 子进程和线程 部分。
以下两个函数可用于自定义 asyncio 事件循环使用的子进程观察器实现:
- asyncio.get_child_watcher()
- 返回当前策略的当前子观察者。
- asyncio.set_child_watcher(watcher)
- 对于当前策略,将当前子观察者设置为 watcher。 watcher 必须实现在 AbstractChildWatcher 基类中定义的方法。
- 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
信号上显式轮询每个进程来避免中断其他代码生成进程。一旦安装了观察者,从不同线程运行子进程就没有限制。
该解决方案是安全的,但在处理大量进程(每次收到
SIGCHLD
时 O(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())