Runner

ソースコード: Lib/asyncio/runners.py

この節では、asyncio のコードを実行するための高レベルの asyncio のプリミティブの概略を解説します。

これらは イベントループ の上に構築されており、一般的な広く普及しているシナリオでの非同期コードの使用を簡素化することを目的としています。

非同期プログラムの実行

asyncio.run(coro, *, debug=None, loop_factory=None)

asyncio のイベントループで coro を実行し、その結果を返します。

引数には任意の awaitable オブジェクトを指定できます。

この関数は awaitable を実行し、asyncio のイベントループの管理、非同期ジェネレーターの終了処理、Executor の終了処理を行います。

この関数は、同じスレッドで他の非同期イベントループが実行中のときは呼び出せません。

debug が True の場合、イベントループはデバッグモードで実行されます。False は明示的にデバッグモードを無効化します。 グローバルな デバッグモード 設定を尊重するために None が使用されます。

loop_factory が None でなければ、それを使って新しいイベントループを作成します。 それ以外の場合は asyncio.new_event_loop() を使います。 終了時にループを閉じます。 この関数は asyncio プログラムのメインのエントリーポイントとして使い、できれば一度だけ呼び出してください。 イベントループの設定には、ポリシーの代わりに loop_factory を使うことを推奨します。 asyncio.EventLoop を渡すと、ポリシーシステムを使わずに asyncio を実行できます。

Executor の終了を待つ制限時間は 5 分です。 その時間内に終了しなければ、警告を出して Executor の終了処理を行います。

以下はプログラム例です:

async def main():
    await asyncio.sleep(1)
    print('hello')

asyncio.run(main())

Added in version 3.7.

バージョン 3.9 で変更: loop.shutdown_default_executor() メソッドを使うように更新されました。

バージョン 3.10 で変更: debug はグローバルなデバッグモード設定を尊重するためにデフォルトで None です。

バージョン 3.12 で変更: loop_factory 引数が追加されました。

バージョン 3.14 で変更: coro に任意の awaitable オブジェクトを指定できるようになりました。

注釈

asyncio のポリシーシステムは非推奨で、Python 3.16 で削除されます。 それ以降、イベントループを設定するには loop_factory を明示的に指定する必要があります。

Runner コンテキストマネージャー

class asyncio.Runner(*, debug=None, loop_factory=None)

同じコンテキスト上での 複数 の非同期関数呼び出しをシンプルにするコンテキストマネージャ。

複数のトップレベルの非同期関数を、同じ イベントループ と contextvars.Context で呼び出したい場合があります。

debug が True の場合、イベントループはデバッグモードで実行されます。False は明示的にデバッグモードを無効化します。 グローバルな デバッグモード 設定を尊重するために None が使用されます。

loop_factory で、ループの作成方法を変更できます。 作成したループを現在のループとして設定するのは loop_factory の役割です。 loop_factory が None の場合は、デフォルトで asyncio.new_event_loop() を使い、asyncio.set_event_loop() で現在のイベントループに設定します。

asyncio.run() の例は、Runner を使って次のように書き換えられます。

async def main():
    await asyncio.sleep(1)
    print('hello')

with asyncio.Runner() as runner:
    runner.run(main())

Added in version 3.11.

run(coro, *, context=None)

内部のイベントループで coro を実行します。

引数には任意の awaitable オブジェクトを指定できます。

引数がコルーチンの場合、Task でラップします。

省略可能なキーワード専用引数 context には、コードの実行に使う contextvars.Context を指定できます。 context が None の場合は、Runner のデフォルトのコンテキストを使います。

awaitable の結果を返すか、例外を送出します。

この関数は、同じスレッドで他の非同期イベントループが実行中のときは呼び出せません。

バージョン 3.14 で変更: coro に任意の awaitable オブジェクトを指定できるようになりました。

close()

Runner を閉じます。

非同期ジェネレーターの終了処理を行い、デフォルトの Executor とイベントループを閉じ、内部の contextvars.Context を解放します。

get_loop()

Runner インスタンスに関連付けられたイベントループを返します。

注釈

Runner は遅延初期化を採用しており、コンストラクターでは内部の低水準なデータ構造を初期化しません。

内部の loop と context は、with 文の本体に入るとき、または run() か get_loop() を初めて呼び出すときに作成されます。

キーボード割り込みの処理

Added in version 3.11.

Ctrl-C で signal.SIGINT が発生すると、デフォルトではメインスレッドで KeyboardInterrupt が送出されます。 しかし asyncio では、内部の処理が中断されてプログラムが終了できなくなる可能性があるため、この動作は適していません。

この問題を軽減するため、asyncio は signal.SIGINT を次のように処理します。

  1. asyncio.Runner.run() はユーザーコードの実行前に独自の signal.SIGINT ハンドラーを設定し、関数を終了するときに取り除きます。

  2. Runner は、渡されたコルーチンを実行するメインタスクを作成します。

  3. Ctrl-C によって signal.SIGINT が発生すると、独自のシグナルハンドラーが asyncio.Task.cancel() を呼び出してメインタスクをキャンセルします。 これにより、メインタスク内で asyncio.CancelledError が送出されます。 Python のスタックが巻き戻されるため、try/except や try/finally ブロックでリソースを解放できます。 メインタスクのキャンセル後、asyncio.Runner.run() は KeyboardInterrupt を送出します。

  4. ユーザーが書いたループが処理を譲らずに繰り返し続け、asyncio.Task.cancel() で中断できない場合があります。 その場合、2 回目の Ctrl-C はメインタスクをキャンセルせず、即座に KeyboardInterrupt を送出します。