ポリシー

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 に設定します。

policyNone の場合、デフォルトポリシーが現在のポリシーに戻されます。

ポリシーオブジェクト

イベントループポリシーの抽象基底クラスは以下のように定義されています:

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 に設定します。 watcherAbstractChildWatcher 基底クラスで定義されたメソッドを実装していなければなりません。

注釈

サードパーティのイベントループ実装は子プロセスのウオッチャーのカスタマイズをサポートしていない可能性があります。そのようなイベントループでは、 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())