# ポリシー

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