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

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" と同様にメインスレッドで
   実行中のイベントループが必要です。


ポリシーのカスタマイズ
======================

新しいイベントループのポリシーを実装するためには、以下に示すように
"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())
