# Futures

原始碼：Lib/asyncio/futures.py、source:`Lib/asyncio/base_futures.py

Future 物件被用來連結低階回呼式程式和高階 async/await 程式。

## Future 函式

asyncio.isfuture(obj)

  如果 obj 為下面任意物件，回傳 `True`：

  - 一個 `asyncio.Future` 的實例、

  - 一個 `asyncio.Task` 的實例、

  - 帶有 `_asyncio_future_blocking` 屬性的類 Future 物件 (Future-like object)。

  在 3.5 版被加入.

asyncio.ensure_future(obj, *, loop=None)

  回傳：

  - obj 引數會保持原樣，obj 須為 `Future`、`Task` 或類 Future 物件（可以用 `isfuture()` 來進行檢查。）

  - 包裝 (wrap) 了 obj 的 `Task` 物件，如果 obj 是一個協程 (coroutine) (可以用 `iscoroutine()` 來進行檢查)；在此情況下該協程將透過 `ensure_future()` 來排程。

  - 一個會等待 obj 的 `Task` 物件，obj 須為一個可等待物件（`inspect.isawaitable()` 用於測試。)

  如果 obj 不是上述物件的話會引發一個 `TypeError` 例外。

  重要

  將參照 (reference) 儲存至此函式的結果，用以防止任務在執行中消失。

  請見 `create_task()` 函式，它是建立新 Task 的推薦方法。或者使用 `asyncio.TaskGroup`，它會在內部保留對 Task 的參照。

  在 3.5.1 版的變更: 這個函式接受任意 awaitable 物件。

  在 3.10 版之後被棄用: 如果 obj 不是類 Future 物件且 loop 並未被指定，同時沒有正在執行的事件迴圈 (event loop)，則會發出棄用警告。

asyncio.wrap_future(future, *, loop=None)

  將一個 `concurrent.futures.Future` 物件包裝到 `asyncio.Future` 物件中。

  在 3.10 版之後被棄用: 如果 future 不是類 Future 物件且 loop 未被指定，同時沒有正在執行的事件迴圈，則會發出棄用警告。

## Future 物件

class asyncio.Future(*, loop=None)

  一個 Future 代表一個非同步運算的最終結果。並不支援執行緒安全 (thread-safe)。

  Future 是一個 awaitable 物件。協程可以等待 Future 物件直到它們有結果或例外被設置、或者被取消。一個 Future 可被多次等待而結果都會是相同的。

  Future 通常用於讓低階基於回呼的程式（例如在協定實作中使用 asyncio transports）能夠與高階 async/await 程式互動。

  經驗法則為永遠不要在提供給使用者的 API 中公開 Future 物件，同時建議使用 `loop.create_future()` 來建立 Future 物件。如此一來，不同實作的事件迴圈可以注入自己最佳化實作的 Future 物件。

  在 3.7 版的變更: 加入對 `contextvars` 模組的支援。

  在 3.10 版之後被棄用: 如果未指定 loop 並且沒有正在執行的事件迴圈則會發出棄用警告。

  result()

    回傳 Future 的結果。

    如果 Future 狀態為 done（完成），並擁有 `set_result()` 方法設定的一個結果，則回傳該結果之值。

    如果 Future 狀態為 done，並擁有 `set_exception()` 方法設定的一個例外，那麼這個方法會引發該例外。

    如果 Future 已被 cancelled（取消），此方法會引發一個 `CancelledError` 例外。

    如果 Future 的結果還不可用，此方法會引發一個 `InvalidStateError` 例外。

  set_result(result)

    將 Future 標記為 done 並設定其結果。

    如果 Future 已經 done 則引發一個 `InvalidStateError` 錯誤。

  set_exception(exception)

    將 Future 標記為 done 並設定一個例外。

    如果 Future 已經 done 則引發一個 `InvalidStateError` 錯誤。

  done()

    如果 Future 已為 done 則回傳 `True`。

    如果 Future 有被 cancelled、`set_result()` 有被呼叫來為其設定結果、或 `set_exception()` 有被呼叫為其設定例外，那麼它就是 done。

  cancelled()

    如果 Future 已經被 cancelled 則回傳 `True`。

    這個方法通常在為 Future 設定結果或例外前用來確認它還沒被 cancelled：

        if not fut.cancelled():
            fut.set_result(42)

  add_done_callback(callback, *, context=None)

    新增一個在 Future 為 done 時執行的回呼函式。

    呼叫 callback 並附帶做為唯一引數的 Future 物件。

    如果呼叫這個方法時 Future 已經為 done，回呼函式會被 `loop.call_soon()` 排程。

    可選僅限關鍵字引數 context 用來指定一個讓 callback 執行於其中的客製化 `contextvars.Context` 物件。如果沒有提供 context，則使用目前情境。

    可以用 `functools.partial()` 傳遞引數給回呼函式，例如：

        # Call 'print("Future:", fut)' when "fut" is done.
        fut.add_done_callback(
            functools.partial(print, "Future:"))

    在 3.7 版的變更: 加入僅限關鍵字參數 context。更多細節請參閱 PEP 567。

  remove_done_callback(callback)

    從回呼列表中移除 callback。

    回傳被移除的回呼函式數量，通常為 1，除非一個回呼函式被多次加入。

  cancel(msg=None)

    取消 Future 並為回呼函式排程。

    如果 Future 已經是 done 或 cancelled，回傳 `False`。否則將 Future 狀態改為 cancelled 並在為回呼函式排程後回傳 `True`。

    在 3.9 版的變更: 新增 msg 參數。

  exception()

    回傳被設定於此 Future 的例外。

    只有 Future 在 done 時才回傳例外（如果沒有設定例外則回傳 `None`）。

    如果 Future 已被 cancelled（取消），此方法會引發一個 `CancelledError` 例外。

    如果 Future 還不為 done，此方法會引發一個 `InvalidStateError` 例外。

  get_loop()

    回傳已被 Future 物件繫結 (bind) 的事件迴圈。

    在 3.7 版被加入.

這個例子建立一個 Future 物件，建立一個非同步 Task 並為其排程以設定 Future 結果，然後等待 Future 結果出現：

    async def set_after(fut, delay, value):
        # Sleep for *delay* seconds.
        await asyncio.sleep(delay)

        # Set *value* as a result of *fut* Future.
        fut.set_result(value)

    async def main():
        # Get the current event loop.
        loop = asyncio.get_running_loop()

        # Create a new Future object.
        fut = loop.create_future()

        # Run "set_after()" coroutine in a parallel Task.
        # We are using the low-level "loop.create_task()" API here because
        # we already have a reference to the event loop at hand.
        # Otherwise we could have just used "asyncio.create_task()".
        loop.create_task(
            set_after(fut, 1, '... world'))

        print('hello ...')

        # Wait until *fut* has a result (1 second) and print it.
        print(await fut)

    asyncio.run(main())

重要

該 Future 物件是為了模仿 `concurrent.futures.Future` 而設計。主要差異包含：

- 與 asyncio 的 Future 不同，`concurrent.futures.Future` 實例不可被等待。

- `asyncio.Future.result()` 和 `asyncio.Future.exception()` 不接受 timeout 引數。

- Future 不為 done 時 `asyncio.Future.result()` 和 `asyncio.Future.exception()` 會引發一個 `InvalidStateError` 例外。

- 使用 `asyncio.Future.add_done_callback()` 註冊的回呼函式不會立即呼叫，而是被 `loop.call_soon()` 排程。

- asyncio Future 不能與 `concurrent.futures.wait()` 和 `concurrent.futures.as_completed()` 函式相容。

- `asyncio.Future.cancel()` 接受一個可選的 `msg` 引數，但 `concurrent.futures.Future.cancel()` 無此引數。