ポリシー
イベントループポリシーは、イベントループの管理を制御するグローバルなプロセスごとのオブジェクトです。 各イベントループにはデフォルトのポリシーがあり、ポリシーAPIを使用して変更およびカスタマイズできます。
ポリシーは、 context の概念を定義し、コンテキストごとに個別のイベントループを管理します。 デフォルトのポリシーでは、 context が現在のスレッドであると定義されています。
カスタムイベントループポリシーを使用することにより、 get_event_loop()、 set_event_loop()、および new_event_loop()関数の動作をカスタマイズできます。
ポリシーオブジェクトは、 AbstractEventLoopPolicy 抽象基本クラスで定義されたAPIを実装する必要があります。
ポリシーの取得と設定
次の関数を使用して、現在のプロセスのポリシーを取得および設定できます。
- asyncio.get_event_loop_policy()
- 現在のプロセス全体のポリシーを返します。
- asyncio.set_event_loop_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
デフォルトの非同期ポリシー。 Unixでは SelectorEventLoop を使用し、Windowsでは ProactorEventLoop を使用します。
デフォルトのポリシーを手動でインストールする必要はありません。 asyncioは、デフォルトのポリシーを自動的に使用するように構成されています。
バージョン3.8で変更: Windowsでは、 ProactorEventLoop がデフォルトで使用されるようになりました。
- class asyncio.WindowsSelectorEventLoopPolicy
- SelectorEventLoop イベントループ実装を使用する代替イベントループポリシー。
- class asyncio.WindowsProactorEventLoopPolicy
- ProactorEventLoop イベントループ実装を使用する代替イベントループポリシー。
プロセスウォッチャー
プロセスウォッチャーを使用すると、イベントループが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)
新しい子ハンドラーを登録します。
PIDが pid に等しいプロセスが終了したときに
callback(pid, returncode, *args)
が呼び出されるように調整します。 同じプロセスに別のコールバックを指定すると、前のハンドラーが置き換えられます。コールバック呼び出し可能オブジェクトはスレッドセーフである必要があります。
- remove_child_handler(pid)
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())