策略
****

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

策略对象 可为每个 *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

   默认的 asyncio 策略。 在 Unix 上使用 "SelectorEventLoop" 而在
   Windows 上使用 "ProactorEventLoop"。

   不需要手动安装默认策略。asyncio已配置成自动使用默认策略。

   3.8 版更變: 在 Windows 上，现在默认会使用 "ProactorEventLoop"。

   備註:

     In Python versions 3.10.9, 3.11.1 and 3.12 the "get_event_loop()"
     method of the default asyncio policy emits a "DeprecationWarning"
     if there is no running event loop and no current loop is set. In
     some future Python release this will become an error.

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

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

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* 相等
      时调用。指定另一个同进程的回调函数替换之前的回调处理函数。

      回调函数 *callback* 必须是线程安全。

   remove_child_handler(pid)

      删除进程PID与 *pid* 相等的进程的处理函数。

      处理函数成功删除时返回 "True" ，没有删除时返回 "False" 。

   attach_loop(loop)

      给一个事件循环绑定监视器。

      如果监视器之前已绑定另一个事件循环，那么在绑定新循环前会先解绑原
      来的事件循环。

      注意：循环有可能是 "None" 。

   is_active()

      如果监视器已准备好使用则返回 "True"。

      使用 *不活动的* 当前子监视器生成子进程将引发 "RuntimeError"。

      3.8 版新加入.

   close()

      关闭监视器。

      必须调用这个方法以确保相关资源会被清理。

class asyncio.ThreadedChildWatcher

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

   即使是当 asyncio 事件循环运行在非主 OS 线程上时它也能可靠地工作。

   当处理大量子进程时不存在显著的开销 (每次子进程结束时为 *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" 是一个“理想的”子进程监视器实现。 它不需要使用
   信号或线程，不会介入任何在事件循环以外发起的进程，并能随事件循环发
   起的子进程数量进行线性伸缩。 其主要缺点在于 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())
