策略

事件循环策略是一个全局对象,用于获取和设置当前的 事件循环,以及创建新的事件循环。默认策略可以 替换内置替代方案 以使用不同的事件循环实现,或者被 自定义策略 替换,该策略可以覆盖这些行为。

策略对象 为每个上下文获取和设置一个单独的事件循环。默认情况下,这是每个线程,尽管自定义策略可以以不同的方式定义上下文

自定义事件循环策略可以控制 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(配置为默认使用)、MultiLoopChildWatcherSafeChildWatcherFastChildWatcher

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

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

asyncio.get_child_watcher()

返回当前策略的当前子进程监视器。

版本 3.12 中已弃用。

asyncio.set_child_watcher(watcher)

将当前策略的当前子进程监视器设置为watcherwatcher 必须实现 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())