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()" 無此引數。
