# Runners

Source code: Lib/asyncio/runners.py

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

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

## 非同期プログラムの実行

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

  coroutine coro を実行し、結果を返します。

  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` が使用されます。

  If loop_factory is not `None`, it is used to create a new event loop; otherwise `asyncio.new_event_loop()` is used. The loop is closed at the end. This function should be used as a main entry point for asyncio programs, and should ideally only be called once. It is recommended to use loop_factory to configure the event loop instead of policies.

  The executor is given a timeout duration of 5 minutes to shutdown. If the executor hasn't finished within that duration, a warning is emitted and the executor is closed.

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

      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 で変更: Added loop_factory parameter.

## Runner context manager

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

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

  Sometimes several top-level async functions should be called in the same event loop and `contextvars.Context`.

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

  loop_factory could be used for overriding the loop creation. It is the responsibility of the loop_factory to set the created loop as the current one. By default `asyncio.new_event_loop()` is used and set as current event loop with `asyncio.set_event_loop()` if loop_factory is `None`.

  Basically, `asyncio.run()` example can be rewritten with the runner usage:

      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()

    Close the runner.

    Finalize asynchronous generators, shutdown default executor, close the event loop and release embedded `contextvars.Context`.

  get_loop()

    Return the event loop associated with the runner instance.

  注釈

  `Runner` uses the lazy initialization strategy, its constructor doesn't initialize underlying low-level structures.

  Embedded loop and context are created at the `with` body entering or the first call of `run()` or `get_loop()`.

## Handling Keyboard Interruption

Added in version 3.11.

When `signal.SIGINT` is raised by ``Ctrl`-`C``, `KeyboardInterrupt` exception is raised in the main thread by default. However this doesn't work with `asyncio` because it can interrupt asyncio internals and can hang the program from exiting.

To mitigate this issue, `asyncio` handles `signal.SIGINT` as follows:

1. `asyncio.Runner.run()` installs a custom `signal.SIGINT` handler before any user code is executed and removes it when exiting from the function.

2. The `Runner` creates the main task for the passed coroutine for its execution.

3. When `signal.SIGINT` is raised by ``Ctrl`-`C``, the custom signal handler cancels the main task by calling `asyncio.Task.cancel()` which raises `asyncio.CancelledError` inside the main task. This causes the Python stack to unwind, `try/except` and `try/finally` blocks can be used for resource cleanup. After the main task is cancelled, `asyncio.Runner.run()` raises `KeyboardInterrupt`.

4. A user could write a tight loop which cannot be interrupted by `asyncio.Task.cancel()`, in which case the second following ``Ctrl`-`C`` immediately raises the `KeyboardInterrupt` without cancelling the main task.