# ポリシー

An event loop policy is a global object used to get and set the current event loop, as well as create new event loops. The default policy can be replaced with built-in alternatives to use different event loop implementations, or substituted by a custom policy that can override these behaviors.

The policy object gets and sets a separate event loop per context. This is per-thread by default, though custom policies could define context differently.

Custom event loop policies can control the behavior of `get_event_loop()`, `set_event_loop()`, and `new_event_loop()`.

ポリシーオブジェクトは `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` がデフォルトで使われるようになりました。

  注釈

  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` 抽象基底クラスを定義しており、さらに異なる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 スレッド上で実行されていても期待通りに動きます。

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

  このウオッチャーはデフォルトで使われます。

  バージョン 3.8 で追加.

class asyncio.MultiLoopChildWatcher

  この実装はインスタンス化の際に `SIGCHLD` シグナルハンドラを登録します。これにより、独自の `SIGCHLD` シグナルハンドラをインストールするようなサードパーティのコードを壊す可能性があります。

  このウオッチャーは、各プロセスに明示的に `SIGCHLD` シグナルをポーリングさせることにより、プロセスを生成する他のコードを中断させないようにします。

  いったんウオッチャーがインストールされると、異なるスレッドからのサブプロセスの実行について特に制限はありません。

  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

  この実装はメインスレッドでアクティブなイベントループを使って `SIGCHLD` シグナルを処理します。メインスレッドでイベントループが実行中でない場合、別のスレッドからサブプロセスを生成することはできません (`RuntimeError` 例外が送出されます)。

  このウオッチャーは、各プロセスに明示的に `SIGCHLD` シグナルをポーリングさせることにより、プロセスを生成する他のコードを中断させないようにします。

  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)` を呼び出します。これにより、プロセスを生成してその終了を待ち受ける別のコードを壊す可能性があります。

  There is no noticeable overhead when handling a big number of children (O(1) each time a child terminates).

  このソリューションは、 `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())