Runner

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

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

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

非同期プログラムの実行

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

Execute the coroutine coro and return the result.

This function runs the passed coroutine, taking care of managing the asyncio event loop, finalizing asynchronous generators, and closing the 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 引数が追加されました。

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)

Run a coroutine coro in the embedded loop.

Return the coroutine's result or raise its exception.

An optional keyword-only context argument allows specifying a custom contextvars.Context for the coro to run in. The runner's default context is used if None.

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

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 を送出します。