策略
****

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

策略定义了“上下文”的概念，每个上下文管理一个单独的事件循环。默认策略将
*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

   The default asyncio policy.  Uses "SelectorEventLoop" on Unix and
   "ProactorEventLoop" on Windows.

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

   在 3.8 版更改: On Windows, "ProactorEventLoop" is now used by
   default.

class asyncio.WindowsSelectorEventLoopPolicy

   An alternative event loop policy that uses the "SelectorEventLoop"
   event loop implementation.

   可用性: Windows。

class asyncio.WindowsProactorEventLoopPolicy

   使用  "ProactorEventLoop" 事件循环实现的另一种事件循环策略。

   可用性: Windows。


进程监视器
==========

进程监视器允许定制事件循环如何监视Unix子进程。具体来说，事件循环需要知
道子进程何时退出。

在asyncio中子进程由  "create_subprocess_exec()" 和
"loop.subprocess_exec()" 函数创建。

asyncio defines the "AbstractChildWatcher" abstract base class, which
child watchers should implement, and has four different
implementations: "ThreadedChildWatcher" (configured to be used by
default), "MultiLoopChildWatcher", "SafeChildWatcher", and
"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()

      Return "True" if the watcher is ready to use.

      Spawning a subprocess with *inactive* current child watcher
      raises "RuntimeError".

      3.8 新版功能.

   close()

      关闭监视器。

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

class asyncio.ThreadedChildWatcher

   This implementation starts a new waiting thread for every
   subprocess spawn.

   It works reliably even when the asyncio event loop is run in a non-
   main OS thread.

   There is no noticeable overhead when handling a big number of
   children (*O(1)* each time a child terminates), but stating a
   thread per process requires extra memory.

   This watcher is used by default.

   3.8 新版功能.

class asyncio.MultiLoopChildWatcher

   This implementation registers a "SIGCHLD" signal handler on
   instantiation. That can break third-party code that installs a
   custom handler for *SIGCHLD*.  signal).

   The watcher avoids disrupting other code spawning processes by
   polling every process explicitly on a "SIGCHLD" signal.

   There is no limitation for running subprocesses from different
   threads once the watcher is installed.

   The solution is safe but it has a significant overhead when
   handling a big number of processes (*O(n)* each time a "SIGCHLD" is
   received).

   3.8 新版功能.

class asyncio.SafeChildWatcher

   This implementation uses active event loop from the main thread to
   handle "SIGCHLD" signal. If the main thread has no running event
   loop another thread cannot spawn a subprocess ("RuntimeError" is
   raised).

   The watcher avoids disrupting other code spawning processes by
   polling every process explicitly on a "SIGCHLD" signal.

   This solution is as safe as "MultiLoopChildWatcher" and has the
   same *O(N)* complexity but requires a running event loop in the
   main thread to work.

class asyncio.FastChildWatcher

   这种实现直接调用  "os.waitpid(-1)" 来获取所有已结束的进程，可能会中
   断其它代码洐生进程并等待它们结束。

   在处理大量子监视器时没有明显的开销( *O(1)*  每次子监视器结束)。

   This solution requires a running event loop in the main thread to
   work, as "SafeChildWatcher".

class asyncio.PidfdChildWatcher

   This implementation polls process file descriptors (pidfds) to
   await child process termination. In some respects,
   "PidfdChildWatcher" is a "Goldilocks" child watcher implementation.
   It doesn't require signals or threads, doesn't interfere with any
   processes launched outside the event loop, and scales linearly with
   the number of subprocesses launched by the event loop. The main
   disadvantage is that pidfds are specific to Linux, and only work on
   recent (5.3+) kernels.

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