策略¶
事件循环策略是一个全局对象,用于获取和设置当前的 事件循环,以及创建新的事件循环。默认策略可以 替换 为 内置替代方案 以使用不同的事件循环实现,或者被 自定义策略 替换,该策略可以覆盖这些行为。
该 策略对象 为每个上下文获取和设置一个单独的事件循环。默认情况下,这是每个线程,尽管自定义策略可以以不同的方式定义上下文。
自定义事件循环策略可以控制 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¶
asyncio 策略的抽象基类。
- get_event_loop()¶
获取当前上下文的事件循环。
返回一个实现
AbstractEventLoop
接口的事件循环对象。此方法不应返回
None
。版本 3.6 中变更。
- set_event_loop(loop)¶
将当前上下文的事件循环设置为loop。
- new_event_loop()¶
创建并返回一个新的事件循环对象。
此方法不应返回
None
。
- get_child_watcher()¶
获取一个子进程监视器对象。
返回一个实现
AbstractChildWatcher
接口的监视器对象。此函数是 Unix 特定的。
版本 3.12 中已弃用。
- set_child_watcher(watcher)¶
将当前子进程监视器设置为watcher。
此函数是 Unix 特定的。
版本 3.12 中已弃用。
asyncio 附带以下内置策略
- class asyncio.DefaultEventLoopPolicy¶
默认的 asyncio 策略。在 Unix 上使用
SelectorEventLoop
,在 Windows 上使用ProactorEventLoop
。无需手动安装默认策略。asyncio 被配置为自动使用默认策略。
版本 3.8 中变更: 在 Windows 上,
ProactorEventLoop
现在默认使用。版本 3.12 中已弃用: 默认 asyncio 策略的
get_event_loop()
方法现在如果当前没有设置事件循环并且它决定创建一个事件循环,则会发出DeprecationWarning
。在未来的某个 Python 版本中,这将成为一个错误。
- 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()¶
返回当前策略的当前子进程监视器。
版本 3.12 中已弃用。
- asyncio.set_child_watcher(watcher)¶
将当前策略的当前子进程监视器设置为watcher。watcher 必须实现
AbstractChildWatcher
基类中定义的方法。版本 3.12 中已弃用。
注意
第三方事件循环实现可能不支持自定义子进程监视器。对于此类事件循环,使用 set_child_watcher()
可能被禁止或没有效果。
- class asyncio.AbstractChildWatcher¶
- add_child_handler(pid, callback, *args)¶
注册一个新的子进程处理程序。
安排在 PID 等于pid 的进程终止时调用
callback(pid, returncode, *args)
。为同一个进程指定另一个回调将替换之前的处理程序。callback 可调用对象必须是线程安全的。
- remove_child_handler(pid)¶
删除 PID 等于pid 的进程的处理程序。
如果处理程序已成功删除,则该函数返回
True
,如果没有任何内容要删除,则返回False
。
- attach_loop(loop)¶
将监视器附加到事件循环。
如果监视器之前已附加到事件循环,则在附加到新循环之前先将其分离。
注意:loop 可能为
None
。
- is_active()¶
如果监视器已准备好使用,则返回
True
。使用非活动的当前子进程监视器生成子进程会引发
RuntimeError
。在版本 3.8 中添加。
- close()¶
关闭监视器。
必须调用此方法以确保清理底层资源。
版本 3.12 中已弃用。
- class asyncio.ThreadedChildWatcher¶
此实现为每个子进程生成启动一个新的等待线程。
即使 asyncio 事件循环在非主 OS 线程中运行,它也能可靠地工作。
处理大量子进程时没有明显的开销(每次子进程终止时为O(1)),但每个进程启动一个线程需要额外的内存。
此监视器默认使用。
在版本 3.8 中添加。
- class asyncio.MultiLoopChildWatcher¶
此实现会在实例化时注册一个
SIGCHLD
信号处理程序。这可能会破坏安装了SIGCHLD
信号的自定义处理程序的第三方代码。监视器通过在
SIGCHLD
信号上显式轮询每个进程来避免干扰其他生成进程的代码。安装监视器后,没有限制从不同线程运行子进程。
该解决方案是安全的,但处理大量进程时开销很大(每次收到
SIGCHLD
时为O(n))。在版本 3.8 中添加。
版本 3.12 中已弃用。
- class asyncio.SafeChildWatcher¶
此实现使用主线程中的活动事件循环来处理
SIGCHLD
信号。如果主线程没有运行事件循环,则另一个线程无法生成子进程(会引发RuntimeError
)。监视器通过在
SIGCHLD
信号上显式轮询每个进程来避免干扰其他生成进程的代码。此解决方案与
MultiLoopChildWatcher
一样安全,并且具有相同的O(n) 复杂度,但需要主线程中运行的事件循环才能工作。版本 3.12 中已弃用。
- class asyncio.FastChildWatcher¶
此实现通过直接调用
os.waitpid(-1)
来收集每个终止的进程,这可能会破坏其他生成进程并等待其终止的代码。处理大量子进程时没有明显的开销(每次子进程终止时为O(1))。
此解决方案需要主线程中运行的事件循环才能工作,与
SafeChildWatcher
一样。版本 3.12 中已弃用。
- 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())