これは既にサポートされていない古いバージョンの Python のドキュメントです。 是非 Python をアップグレードし、このドキュメントを読みましょう: 現在の安定板リリースの Python ドキュメント.

# コルーチンと Task

この節では、コルーチンと Task を利用する高レベルの asyncio の API の概略を解説します。

- コルーチン

- Awaitable

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

- Task の作成

- スリープ

- 並行な Task 実行

- キャンセルからの保護

- タイムアウト

- 要素の待機

- 外部スレッドからのスケジュール

- イントロスペクション

- Task オブジェクト

- Generator-based Coroutines

## コルーチン

async/await 構文で宣言されたコルーチンは、 asyncio を使ったアプリケーションを書く手法として好ましいです。 例えば、次のコードスニペット (Python 3.7 以降が必要) は "hello" を出力し、そこから 1 秒待って "world" を出力します:

    >>> import asyncio

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

    >>> asyncio.run(main())
    hello
    world

単にコルーチンを呼び出しただけでは、コルーチンの実行スケジュールは予約されていないことに注意してください:

    >>> main()
    <coroutine object main at 0x1053bb7c8>

実際にコルーチンを走らせるために、 asyncio は3つの機構を提供しています:

- 最上位のエントリーポイントである "main()" 関数を実行する `asyncio.run()` 関数 (上の例を参照してください。)

- コルーチンを await すること。次のコード片は 1 秒間待機した後に "hello" と出力し、 更に 2 秒間待機してから "world" と出力します:

      import asyncio
      import time

      async def say_after(delay, what):
          await asyncio.sleep(delay)
          print(what)

      async def main():
          print(f"started at {time.strftime('%X')}")

          await say_after(1, 'hello')
          await say_after(2, 'world')

          print(f"finished at {time.strftime('%X')}")

      asyncio.run(main())

  予想される出力:

      started at 17:13:52
      hello
      world
      finished at 17:13:55

- asyncio の `Tasks` としてコルーチンを並行して走らせる `asyncio.create_task()` 関数。

  上のコード例を編集して、ふたつの `say_after` コルーチンを 並行して 走らせてみましょう:

      async def main():
          task1 = asyncio.create_task(
              say_after(1, 'hello'))

          task2 = asyncio.create_task(
              say_after(2, 'world'))

          print(f"started at {time.strftime('%X')}")

          # Wait until both tasks are completed (should take
          # around 2 seconds.)
          await task1
          await task2

          print(f"finished at {time.strftime('%X')}")

  予想される出力が、スニペットの実行が前回よりも 1 秒早いことを示していることに注意してください:

      started at 17:14:32
      hello
      world
      finished at 17:14:34

## Awaitable

あるオブジェクトを `await` 式の中で使うことができる場合、そのオブジェクトを awaitable オブジェクトと言います。多くの asyncio API は awaitable を受け取るように設計されています。

awaitable オブジェクトには主に3つの種類があります: コルーチン, Task, そして Future です

コルーチン

Python のコルーチンは awaitable であり、そのため他のコルーチンを待機させられます:

    import asyncio

    async def nested():
        return 42

    async def main():
        # Nothing happens if we just call "nested()".
        # A coroutine object is created but not awaited,
        # so it *won't run at all*.
        nested()

        # Let's do it differently now and await it:
        print(await nested())  # will print "42".

    asyncio.run(main())

重要

このドキュメントにおいて「コルーチン」という用語は以下2つの密接に関連した概念に対して使用できます:

- コルーチン関数: `async def` 関数;

- コルーチンオブジェクト: コルーチン関数 を呼び出すと返ってくるオブジェクト.

asyncio は、古くからある ジェネレータベース のコルーチンもサポートしています。

Task

Task は、コルーチンを 並行に スケジュールするのに使います。

`asyncio.create_task()` のような関数で、コルーチンが Task にラップされているとき、自動的にコルーチンは即時実行されるようにスケジュールされます:

    import asyncio

    async def nested():
        return 42

    async def main():
        # Schedule nested() to run soon concurrently
        # with "main()".
        task = asyncio.create_task(nested())

        # "task" can now be used to cancel "nested()", or
        # can simply be awaited to wait until it is complete:
        await task

    asyncio.run(main())

Future

`Future` は、非同期処理の 最終結果 を表現する特別な 低レベルの awaitable オブジェクトです。

Future オブジェクトが他の awaitable を 待機させている と言うときは、ある場所で Future が解決されるまでコルーチンが待機するということです。

asyncio での Future オブジェクトは、async/await と共に使用できるようにするため、コールバック形式のコードを使用できるように設計すべきです。

通常、アプリケーション水準のコードで Future オブジェクトを作る 必要はありません 。

Future オブジェクトはライブラリや asyncio の API で表に出ることもあり、他の awaitable を待機させられます:

    async def main():
        await function_that_returns_a_future_object()

        # this is also valid:
        await asyncio.gather(
            function_that_returns_a_future_object(),
            some_python_coroutine()
        )

Future オブジェクトを返す低レベル関数の良い例は `loop.run_in_executor()` です。

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

`asyncio.``run`(coro, *, debug=False)

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

  この関数は、非同期イベントループの管理と 非同期ジェネレータの終了処理 を行いながら、渡されたコルーチンを実行します。

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

  debug が `True` の場合、イベントループはデバッグモードで実行されます。

  この関数は常に新しいイベントループを作成し、終了したらそのイベントループを閉じます。 この関数は非同期プログラムのメインのエントリーポイントとして使われるべきで、理想的には 1 回だけ呼び出されるべきです。

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

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

      asyncio.run(main())

  バージョン 3.7 で追加: 重要: この関数は Python 3.7 で 暫定 API として asyncio に追加されました。

## Task の作成

`asyncio.``create_task`(coro)

  coro coroutine を `Task` でラップし、その実行をスケジュールします。 Task オブジェクトを返します。

  その Task オブジェクトは `get_running_loop()` から返されたループの中で実行されます。現在のスレッドに実行中のループが無い場合は、 `RuntimeError` が送出されます。

  この関数は Python 3.7 で追加 されました。 Python 3.7 より前では、代わりに低レベルの `asyncio.ensure_future()` 関数が使えます:

      async def coro():
          ...

      # In Python 3.7+
      task = asyncio.create_task(coro())
      ...

      # This works in all Python versions but is less readable
      task = asyncio.ensure_future(coro())
      ...

  バージョン 3.7 で追加.

## スリープ

coroutine `asyncio.``sleep`(delay, result=None, *, loop=None)

  delay 秒だけ停止します。

  result が提供されている場合は、コルーチン完了時にそれが呼び出し元に返されます。

  `sleep()` は常に現在の Task を一時中断し、他の Task が実行されるのを許可します。

  loop 引数は非推奨で、 Python 3.10 で削除される予定です。

  現在の時刻を5秒間、毎秒表示するコルーチンの例:

      import asyncio
      import datetime

      async def display_date():
          loop = asyncio.get_running_loop()
          end_time = loop.time() + 5.0
          while True:
              print(datetime.datetime.now())
              if (loop.time() + 1.0) >= end_time:
                  break
              await asyncio.sleep(1)

      asyncio.run(display_date())

## 並行な Task 実行

awaitable `asyncio.``gather`(*aws, loop=None, return_exceptions=False)

  aws シーケンスにある awaitable オプジェクト を 並行 実行します。

  aws にある awaitable がコルーチンである場合、自動的に Task としてスケジュールされます。

  全ての awaitable が正常終了した場合、その結果は返り値を集めたリストになります。 返り値の順序は、 aws での awaitable の順序に相当します。

  return_exceptions が `False` である場合(デフォルト)、`gather()` で await しているタスクに対して、最初の例外が直接伝えられます。aws に並んでいる他の awaitable は、キャンセルされずに 引き続いて実行されます。

  return_exceptions が `True` だった場合、例外は成功した結果と同じように取り扱われ、結果リストに集められます。

  `gather()` が キャンセル された場合、起動された全ての (未完了の) awaitable も キャンセル されます。

  aws シーケンスにある Task あるいは Future が キャンセル された場合、 `CancelledError` を送出したかのうように扱われます。つまり、この場合 `gather()` 呼び出しはキャンセル されません。 これは、起動された 1 つの Task あるいは Future のキャンセルが、他の Task あるいは Future のキャンセルを引き起こすのを避けるためです。

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

      import asyncio

      async def factorial(name, number):
          f = 1
          for i in range(2, number + 1):
              print(f"Task {name}: Compute factorial({i})...")
              await asyncio.sleep(1)
              f *= i
          print(f"Task {name}: factorial({number}) = {f}")

      async def main():
          # Schedule three calls *concurrently*:
          await asyncio.gather(
              factorial("A", 2),
              factorial("B", 3),
              factorial("C", 4),
          )

      asyncio.run(main())

      # Expected output:
      #
      #     Task A: Compute factorial(2)...
      #     Task B: Compute factorial(2)...
      #     Task C: Compute factorial(2)...
      #     Task A: factorial(2) = 2
      #     Task B: Compute factorial(3)...
      #     Task C: Compute factorial(3)...
      #     Task B: factorial(3) = 6
      #     Task C: Compute factorial(4)...
      #     Task C: factorial(4) = 24

  バージョン 3.7 で変更: gather 自身がキャンセルされた場合は、 return_exceptions の値に関わらずキャンセルが伝搬されます。

## キャンセルからの保護

awaitable `asyncio.``shield`(aw, *, loop=None)

  `キャンセル` から awaitable オプジェクト を保護します。

  aw がコルーチンだった場合、自動的に Task としてスケジュールされます。

  文:

      res = await shield(something())

  は、以下と同じです

      res = await something()

  それを含むコルーチンがキャンセルされた場合を 除き、`something()` 内で動作している Task はキャンセルされません。 `something()` 側から見るとキャンセルは発生しません。 呼び出し元がキャンセルされた場合でも、 "await" 式は `CancelledError` を送出します。

  注意: `something()` が他の理由 (例えば、原因が自分自身) でキャンセルされた場合は `shield()` でも保護できません。

  完全にキャンセルを無視したい場合 (推奨はしません) は、 `shield()` 関数は次のように try/except 節と組み合わせることになるでしょう:

      try:
          res = await shield(something())
      except CancelledError:
          res = None

## タイムアウト

coroutine `asyncio.``wait_for`(aw, timeout, *, loop=None)

  aw awaitable が、完了するかタイムアウトになるのを待ちます。

  aw がコルーチンだった場合、自動的に Task としてスケジュールされます。

  timeout には `None` もしくは待つ秒数の浮動小数点数か整数を指定できます。 timeout が `None` の場合、 Future が完了するまで待ちます。

  タイムアウトが起きた場合は、 Task をキャンセルし `asyncio.TimeoutError` を送出します。

  Task の `キャンセル` を避けるためには、 `shield()` の中にラップしてください。

  この関数は、 Future が実際にキャンセルされるまで待つので、全体の待ち時間は timeout を超えることもあります。

  待機が中止された場合 aw も中止されます。

  loop 引数は非推奨で、 Python 3.10 で削除される予定です。

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

      async def eternity():
          # Sleep for one hour
          await asyncio.sleep(3600)
          print('yay!')

      async def main():
          # Wait for at most 1 second
          try:
              await asyncio.wait_for(eternity(), timeout=1.0)
          except asyncio.TimeoutError:
              print('timeout!')

      asyncio.run(main())

      # Expected output:
      #
      #     timeout!

  バージョン 3.7 で変更: aw がタイムアウトでキャンセルされたとき、 `wait_for` は aw がキャンセルされるまで待ちます。 以前は、すぐに `asyncio.TimeoutError` を送出していました。

## 要素の待機

coroutine `asyncio.``wait`(aws, *, loop=None, timeout=None, return_when=ALL_COMPLETED)

  aws 集合にある awaitable オブジェクト を 並行 実行し、 return_when で指定した条件が満たされるまで待ちます。

  aws にある awaitable のどれかがコルーチンの場合、自動的に Task としてスケジュールされます。 コルーチンオブジェクトを `wait()` に直接渡すのは 紛らわしい振る舞い を引き起こすため非推奨です。

  Task と Future の 2 つ `(done, pending)` を返します。

  使い方:

      done, pending = await asyncio.wait(aws)

  loop 引数は非推奨で、 Python 3.10 で削除される予定です。

  timeout (浮動小数点数または整数) が指定されていたら、処理を返すのを待つ最大秒数を制御するのに使われます。

  この関数は `asyncio.TimeoutError` を送出しないことに注意してください。 タイムアウトが起きたときに完了していなかった Future や Task は、2 つ目の集合の要素として返されるだけです。

  return_when でこの関数がいつ結果を返すか指定します。指定できる値は以下の 定数のどれか一つです:

  定数 | 説明
  --- | ---
  `FIRST_COMPLETED` | いずれかの Future が終了したかキャンセルされたときに返します。
  `FIRST_EXCEPTION` | いずれかの Future が例外の送出で終了した場合に返します。 例外を送出したフューチャがない場合は、`ALL_COMPLETED` と等価になります。
  `ALL_COMPLETED` | すべての Future が終了したかキャンセルされたときに返します。

  `wait_for()` と異なり、 `wait()` はタイムアウトが起きたときに Future をキャンセルしません。

  注釈

  `wait()` は自動的にコルーチンを Task としてスケジュールし、その後、暗黙的に作成された Task オブジェクトを組になった集合 `(done, pending)` に入れて返します。 従って、次のコードは予想した通りには動作しません:

      async def foo():
          return 42

      coro = foo()
      done, pending = await asyncio.wait({coro})

      if coro in done:
          # This branch will never be run!

  上のスクリプト片は次のように修正できます:

      async def foo():
          return 42

      task = asyncio.create_task(foo())
      done, pending = await asyncio.wait({task})

      if task in done:
          # Everything will work as expected now.

  `wait()` にコルーチンオブジェクトを直接渡すのは非推奨です。

`asyncio.``as_completed`(aws, *, loop=None, timeout=None)

  Run awaitable objects in the aws set concurrently. Return an iterator of `Future` objects. Each Future object returned represents the earliest result from the set of the remaining awaitables.

  全フューチャが終了する前にタイムアウトが発生した場合 `asyncio.TimeoutError` を送出します。

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

      for f in as_completed(aws):
          earliest_result = await f
          # ...

## 外部スレッドからのスケジュール

`asyncio.``run_coroutine_threadsafe`(coro, loop)

  与えられたイベントループにコルーチンを送ります。 この処理は、スレッドセーフです。

  他の OS スレッドから結果を待つための `concurrent.futures.Future` を返します。

  この関数は、イベントループが動作しているスレッドとは異なる OS スレッドから呼び出すためのものです。 例えば次のように使います:

      # Create a coroutine
      coro = asyncio.sleep(1, result=3)

      # Submit the coroutine to a given loop
      future = asyncio.run_coroutine_threadsafe(coro, loop)

      # Wait for the result with an optional timeout argument
      assert future.result(timeout) == 3

  コルーチンから例外が送出された場合、返された Future に通知されます。 これはイベントループの Task をキャンセルするのにも使えます:

      try:
          result = future.result(timeout)
      except asyncio.TimeoutError:
          print('The coroutine took too long, cancelling the task...')
          future.cancel()
      except Exception as exc:
          print(f'The coroutine raised an exception: {exc!r}')
      else:
          print(f'The coroutine returned: {result!r}')

  このドキュメントの asyncio-multithreading 節を参照してください。

  他の asyncio 関数とは異なり、この関数は明示的に渡される loop 引数を必要とします。

  バージョン 3.5.1 で追加.

## イントロスペクション

`asyncio.``current_task`(loop=None)

  現在実行中の `Task` インスタンスを返します。実行中の Task が無い場合は `None` を返します。

  loop が `None` の場合、 `get_running_loop()` が現在のループを取得するのに使われます。

  バージョン 3.7 で追加.

`asyncio.``all_tasks`(loop=None)

  ループで実行された `Task` オブジェクトでまだ完了していないものの集合を返します。

  loop が `None` の場合、 `get_running_loop()` は現在のループを取得するのに使われます。

  バージョン 3.7 で追加.

## Task オブジェクト

class `asyncio.``Task`(coro, *, loop=None)

  Python コルーチン を実行する `Future 類` オブジェクトです。 スレッドセーフではありません。

  Task はイベントループのコルーチンを実行するのに使われます。 Future でコルーチンが待機している場合、 Task は自身のコルーチンの実行を一時停止させ、 Future の完了を待ちます。 Future が 完了 したら、 Task が内包しているコルーチンの実行を再開します。

  イベントループは協調スケジューリングを使用します。つまり、イベントループは同時に 1 つの Task のみ実行します。 Task が Future の完了を待っているときは、イベントループは他の Task やコールバックを動作させるか、 IO 処理を実行します。

  Task を作成するには高レベルの `asyncio.create_task()` 関数、あるいは低レベルの `loop.create_task()` 関数や `ensure_future()` 関数を使用してください。 手作業での Task の実装は推奨されません。

  実行中のタスクをキャンセルするためには、`cancel()` メソッドを使用します。このメソッドを呼ぶと、タスクはそれを内包するコルーチンに対して `CancelledError` 例外を送出します。キャンセルの際にコルーチンが Future オブジェクトを待っていた場合、その Future オブジェクトはキャンセルされます。

  `cancelled()` は、タスクがキャンセルされたかを調べるのに使用できます。タスクを内包するコルーチンで `CancelledError` 例外が抑制されておらず、かつタスクが実際にキャンセルされている場合に、このメソッドは `True` を変えます。

  `asyncio.Task` は、`Future.set_result()` と `Future.set_exception()` を除いて、`Future` の API をすべて継承しています。

  Task は `contextvars` モジュールをサポートします。Task が作られたときに現在のコンテキストがコピーされ、のちに Task のコルーチンを実行する際に、コピーされたコンテキストが使用されます。

  バージョン 3.7 で変更: `contextvars` モジュールのサポートを追加。

  `cancel`()

    このタスクに、自身のキャンセルを要求します。

    This arranges for a `CancelledError` exception to be thrown into the wrapped coroutine on the next cycle of the event loop.

    The coroutine then has a chance to clean up or even deny the request by suppressing the exception with a `try` ... ... `except CancelledError` ... `finally` block. Therefore, unlike `Future.cancel()`, `Task.cancel()` does not guarantee that the Task will be cancelled, although suppressing cancellation completely is not common and is actively discouraged.

    The following example illustrates how coroutines can intercept the cancellation request:

        async def cancel_me():
            print('cancel_me(): before sleep')

            try:
                # Wait for 1 hour
                await asyncio.sleep(3600)
            except asyncio.CancelledError:
                print('cancel_me(): cancel sleep')
                raise
            finally:
                print('cancel_me(): after sleep')

        async def main():
            # Create a "cancel_me" Task
            task = asyncio.create_task(cancel_me())

            # Wait for 1 second
            await asyncio.sleep(1)

            task.cancel()
            try:
                await task
            except asyncio.CancelledError:
                print("main(): cancel_me is cancelled now")

        asyncio.run(main())

        # Expected output:
        #
        #     cancel_me(): before sleep
        #     cancel_me(): cancel sleep
        #     cancel_me(): after sleep
        #     main(): cancel_me is cancelled now

  `cancelled`()

    Return `True` if the Task is cancelled.

    The Task is cancelled when the cancellation was requested with `cancel()` and the wrapped coroutine propagated the `CancelledError` exception thrown into it.

  `done`()

    Return `True` if the Task is done.

    A Task is done when the wrapped coroutine either returned a value, raised an exception, or the Task was cancelled.

  `result`()

    Return the result of the Task.

    If the Task is done, the result of the wrapped coroutine is returned (or if the coroutine raised an exception, that exception is re-raised.)

    If the Task has been cancelled, this method raises a `CancelledError` exception.

    If the Task's result isn't yet available, this method raises a `InvalidStateError` exception.

  `exception`()

    Return the exception of the Task.

    If the wrapped coroutine raised an exception that exception is returned. If the wrapped coroutine returned normally this method returns `None`.

    If the Task has been cancelled, this method raises a `CancelledError` exception.

    If the Task isn't done yet, this method raises an `InvalidStateError` exception.

  `add_done_callback`(callback, *, context=None)

    Add a callback to be run when the Task is done.

    This method should only be used in low-level callback-based code.

    See the documentation of `Future.add_done_callback()` for more details.

  `remove_done_callback`(callback)

    コールバックリストから callback を削除します。

    This method should only be used in low-level callback-based code.

    See the documentation of `Future.remove_done_callback()` for more details.

  `get_stack`(*, limit=None)

    Return the list of stack frames for this Task.

    If the wrapped coroutine is not done, this returns the stack where it is suspended. If the coroutine has completed successfully or was cancelled, this returns an empty list. If the coroutine was terminated by an exception, this returns the list of traceback frames.

    フレームは常に古いものから新しい物へ並んでいます。

    Only one stack frame is returned for a suspended coroutine.

    The optional limit argument sets the maximum number of frames to return; by default all available frames are returned. The ordering of the returned list differs depending on whether a stack or a traceback is returned: the newest frames of a stack are returned, but the oldest frames of a traceback are returned. (This matches the behavior of the traceback module.)

  `print_stack`(*, limit=None, file=None)

    Print the stack or traceback for this Task.

    This produces output similar to that of the traceback module for the frames retrieved by `get_stack()`.

    The limit argument is passed to `get_stack()` directly.

    The file argument is an I/O stream to which the output is written; by default output is written to `sys.stderr`.

  classmethod `all_tasks`(loop=None)

    イベントループのすべての Task の集合を返します。

    By default all tasks for the current event loop are returned. If loop is `None`, the `get_event_loop()` function is used to get the current loop.

    This method is deprecated and will be removed in Python 3.9. Use the `asyncio.all_tasks()` function instead.

  classmethod `current_task`(loop=None)

    Return the currently running task or `None`.

    If loop is `None`, the `get_event_loop()` function is used to get the current loop.

    This method is deprecated and will be removed in Python 3.9. Use the `asyncio.current_task()` function instead.

## Generator-based Coroutines

注釈

Support for generator-based coroutines is deprecated and is scheduled for removal in Python 3.10.

Generator-based coroutines predate async/await syntax. They are Python generators that use `yield from` expressions to await on Futures and other coroutines.

Generator-based coroutines should be decorated with `@asyncio.coroutine`, although this is not enforced.

`@``asyncio.``coroutine`

  Decorator to mark generator-based coroutines.

  This decorator enables legacy generator-based coroutines to be compatible with async/await code:

      @asyncio.coroutine
      def old_style_coroutine():
          yield from asyncio.sleep(1)

      async def main():
          await old_style_coroutine()

  This decorator is deprecated and is scheduled for removal in Python 3.10.

  This decorator should not be used for `async def` coroutines.

`asyncio.``iscoroutine`(obj)

  obj が コルーチンオブジェクト であれば `True` を返します。

  This method is different from `inspect.iscoroutine()` because it returns `True` for generator-based coroutines.

`asyncio.``iscoroutinefunction`(func)

  Return `True` if func is a coroutine function.

  This method is different from `inspect.iscoroutinefunction()` because it returns `True` for generator-based coroutine functions decorated with `@coroutine`.