ポリシー
********

An event loop policy is a global per-process object that controls the
management of the event loop. Each event loop has a default policy,
which can be changed and customized using the policy API.

A policy defines the notion of *context* and manages a separate event
loop per context. The default policy defines *context* to be the
current thread.

By using a custom event loop policy, the behavior of
"get_event_loop()", "set_event_loop()", and "new_event_loop()"
functions can be customized.

ポリシーオブジェクトは "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 特有です。

   set_child_watcher(watcher)

      子プロセスに対する現在のウオッチャーオブジェクトを *watcher* に
      設定します。

      この関数は Unix 特有です。

asyncio は以下の組み込みポリシーを提供します:

class asyncio.DefaultEventLoopPolicy

   デフォルトの asyncio ポリシーです。Unix では "SelectorEventLoop" 、
   Windows では "ProactorEventLoop" を使います。

   デフォルトのポリシーを手動でインストールする必要はありません。
   asyncio はデフォルトポリシーを使うように自動的に構成されます。

   バージョン 3.8 で変更: Windows では "ProactorEventLoop" がデフォル
   トで使われるようになりました。

class asyncio.WindowsSelectorEventLoopPolicy

   "SelectorEventLoop" イベントループ実装を使った別のイベントループポ
   リシーです。

   利用可能な環境: Windows 。

class asyncio.WindowsProactorEventLoopPolicy

   "ProactorEventLoop" イベントループ実装を使った別のイベントループポ
   リシーです。

   利用可能な環境: Windows 。


プロセスのウオッチャー
======================

プロセスのウオッチャーは Unix 上でイベントループが子プロセスを監視する
方法をカスタマイズすることを可能にします。特に、子プロセスがいつ終了し
たかをイベントループは知る必要があります。

asyncio では、子プロセスは "create_subprocess_exec()" や
"loop.subprocess_exec()" 関数により生成されます。

asyncio は、子プロセスのウオッチャーが実装すべき
"AbstractChildWatcher" 抽象基底クラスを定義しており、さらに異なる4つの
実装クラスを提供しています: "ThreadedChildWatcher" (デフォルトでこのク
ラスが使われるように構成されます), "MultiLoopChildWatcher",
"SafeChildWatcher", そして "FastChildWatcher" です。

サブプロセスとスレッド 節も参照してください。

以下の2つの関数は 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)

      新しい子プロセスのハンドラを登録します。

      プロセス ID (PID) が *pid* であるプロセスが終了した時に
      "callback(pid, returncode, *args)" コールバック関数が呼び出され
      るように手配します。同じプロセスに対して別のコールバックを登録し
      た場合、以前登録したハンドラを置き換えます。

      *callback* はスレッドセーフな呼び出し可能オブジェクトでなければ
      なりません。

   remove_child_handler(pid)

      プロセス ID (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" は "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())
