Future與promise

在電腦科學中，future、promise、delay和deferred，是在某些並發程式語言中，指稱用於同步程序執行的一種構造。由於某些計算尚未結束，故而需要一個對象來代理這個未知的結果。這種構造起源於函數式編程和相關范型如邏輯編程，其目的是將值與其運算過程解耦，從而允許更靈活地進行計算，特別是通過將其並行化來進行。後來它在分布式計算中得到了應用，用來減少網路通信往返的延遲。再後來async/await語法機制使其變得更有用，籍此允許以直接風格編寫異步程序，而不再採用續體傳遞風格。

## 術語

在1976年Daniel P. Friedman和David Wise提出了術語「promise」，同年Peter Hibbard稱之為「eventual」。1977年Henry Baker和Carl Hewitt在一篇論文中介紹了一個類似的概念「future」。

術語「future」、「promise」、「delay」和「deferred」通常用來稱謂同樣一種機制，在特定實現中可能只選用其中之一。在這種情況下，值與其運算過程是一起創建並且相互關聯的：future若指稱推遲設置的一個值，設置它的函數就可稱謂為promise；promise若指稱推遲設置的一個值，設置它的函數就可稱謂為resolver；promise若指稱一個異步函數，它的結果值所設置的就可稱謂為future。設置一個推遲值也稱為「決定/解決」（resolve）、「履行/實現」（fulfil）或「綁定」（bind）它。

推遲值及其設置者也存在區分稱謂而同時使用的情況，二者的這種用法在不同實現中的差異將在專門章節中討論。具體來說，future指稱一個「只讀」的變量的占位符視圖，而promise指稱一個可寫的單賦值容器，使用其「成功」方法來設置這個future的值。尤其是在定義future之時，無須指定設置其值的promise；並且可能有不同的promise，設置同一個future的值；但是對於一個給定future，僅可以進行一次設置。

## 歷史

future及/或promise構造，首先實現於程式語言例如MultiLisp和Act 1之中。在並發邏輯程式語言中，使用非常類似於future的邏輯變量進行通信。這種語言開始於1982年的「Prolog with Freeze」和「IC Prolog」，並且在後來的語言中變成了真正的並發原語，比如Concurrent Prolog、Parlog、守衛霍恩子句（GHC）、Strand語言、Janus語言、Oz（Mozart）和Alice語言。叫做「I-變量」的單賦值變量，非常類似於並發邏輯變量，它起源於數據流程程式語言Id語言的「I-結構」元件，並且包含在Reppy的Concurrent ML中。

在1988年Barbara Liskov和Liuba Shrira，發明了promise流水線技術來克服傳輸延遲；Liskov和Shrira在論文中使用了術語「promise」，但是他們採用了現在少見的名稱「call-stream」來提及流水線機制。在大約1989年Mark S. Miller、Dean Tribble和Rob Jellinghaus，於Xanadu項目中也獨立發明了此技術。

Liskov和Shrira的論文中描述的設計，以及Xanadu中的promise流水線的實現，都有一個限制，即promise值不是頭等的：call或send的參數或返回值，不能直接是promise。在Liskov和Shrira論文中使用的程式語言Argus，直至大約1988年停止開發，似乎都未曾在任何公開發布中實現promise和call-stream。Xanadu實現的promise流水線，僅在1999年Udanax Gold的原始碼發布時才公開發布，並且在任何已發布的文檔中都沒有解釋過。

一些早期的演員語言，包括Act系列，支持並行消息傳遞和流水線式消息處理，但不支持promise流水線。Joule語言和E語言的後續實現，支持完全頭等的promise和resolver，還有promise流水線。

2000年之後，由於消息模式的請求-響應模型，在使用者界面響應力和Web開發中的應用，future和promise重新引起了人們的興趣。現在一些主流語言對future和promise有了語言支持，最著名的是2004年發行的Java 5中的`FutureTask`，以及2012年發行的.NET框架 4.5中的`async`/`await`結構，它在很大程度上受到可追溯到2007年的「F#異步編程模型」的啟發。async/await隨後被其他語言採用，特別是2014年的Dart 1.9、2014年發行的Hack（HHVM）、2015年的Python 3.5、ECMAScript 2017、2019年的Rust 1.39和C++20等。

## 程式語言典型示例

### Python

Python的`concurrent.futures`模塊，提供了異步 (電腦編程)程序執行可調用對象的高層接口。異步執行可以使用線程池執行器`ThreadPoolExecutor`，通過多個線程來進行；或使用進程池 (電腦科學)執行器`ProcessPoolExecutor`，通過分立的多個進程來進行。`concurrent.futures.Future`類封裝了可調用對象的異步執行，其實例由執行器抽象類`Executor`的這兩個子類的`submit()`方法創建。

在下面的例子中，定義了`load_url()`，用來檢索一個URL所指定的單一網頁並報告其內容。使用`with`語句指定採用線程池執行器，這確保了線程由它及時清理。用這個執行器的`submit()`方法啟動所有的裝載操作任務，並使用字典推導式為其創建的每個future標記上對應的URL。採用模塊函數`as_completed()`，在指定的`Future`類的諸實例「已齊全」（completed）之時，建立在其上的迭代器。

```python
import concurrent.futures
import urllib.request

URLS = [
    'https://www.python.org/',
    'https://pypi.org/search/',
    'https://no-such-url']

def load_url(url, timeout):
    with urllib.request.urlopen(url, timeout=timeout) as conn:
        return conn.read()

with concurrent.futures.ThreadPoolExecutor() as executor:
    future_to_url = {executor.submit(load_url, url, 60) : url for url in URLS}
    for future in concurrent.futures.as_completed(future_to_url):
        url = future_to_url[future]
        try:
            data = future.result()
        except Exception as exc:
            print(f'{url!r} generated an exception: {exc!s}')
        else:
            print(f'{url!r} page is {len(data):d} bytes')
```

在CPython中，由於全局解釋器鎖（GIL），保證一時只有一個線程可以執行Python字節碼；一些擴展模塊被設計為在進行計算密集任務時釋放GIL，還有在進行I/O時總是釋放GIL。線程池執行器的`max_workers`參數的預設值是`min(32, os.cpu_count() + 4)`，這個預設值為I/O踴躍任務保留至少5個worker線程，為釋放GIL的CPU踴躍任務利用最多32個CPU邏輯核心。想要更好利用多核心機器的計算資源，可以使用進程池執行器或多進程模塊`multiprocessing`。對於同時運行多個I/O踴躍任務，仍然適合採用線程池執行器或線程模塊`threading`。

Python的異步I/O模塊`asyncio`，是採用async/await語法編寫並發代碼的庫。`asyncio`模塊基於低層事件循環，提供的高層API包括了：並發運行Python協程並擁有在其執行上的完全控制，進行網路IO和IPC，控制子進程，通過隊列分布任務 (計算)和同步並發代碼。`asyncio`模塊的同步原語，在設計上類似於`threading`模塊的同步原語，但與之相比有兩個重要差異：`asyncio`模塊的同步原語不是線程安全的，故而不能用於OS線程同步；這些同步原語的方法不接受超時 (計算)實際參數。

`asyncio`模塊提供的低層API中有`asyncio.Future`對象，用來橋接低層基於回調的代碼和高層採用`async`/`await`語法的代碼，它在設計上模仿了`concurrent.futures.Future`對象。這兩個模塊的`Future`對象的`set_result()`方法標記這個`Future`對象為「已完畢」（done）並設置它的結果，而`set_exception()`方法標記這個`Future`對象為已完畢並設置一個例外；`done()`方法在這個`Future`對象已完畢時返回`True`；`result()`方法返回這個`Future`對象所設置的結果，或者引發其所設置的例外。

二者的關鍵差異包括了：`asyncio.Future`是可期待（awaitable）對象，而`concurrent.futures.Future`對象不可以被期待（awaited）。`asyncio.Future.result()`不接受超時實際參數，如果此刻這個`Future`對象的結果仍不可獲得，它引發一個`InvalidStateError`例外；而`concurrent.futures.Future.result()`，可接受超時 (計算)（`timeout`）實際參數，如果此刻結果仍未「完全」（completed），它等待指定時間後若仍未完全則引發`TimeoutError`例外，如果超時未指定或指定為`None`，則對等待時間沒有限制。

### JavaScript

在JavaScript中，`Promise`對象表示一個異步 (電腦編程)運算的最終完成或失敗，及其結果值或失敗理由。`Promise`對象是對一個值的代理（proxy），這個值在創建這個promise之時不必需已知。promise允許為異步行動的最終成功值或失敗理由關聯上處理器，這使得異步方法像同步方法那樣返回值：並非立即返回最終值，異步方法返回一個promise來在將來的某一點上提供這個值。

在JavaScript生態系統中，`Promise`對象在成為語言本身的一部份之前很久就有了多種實現。儘管各有不同的內部表示，至少幾乎所有類似`Promise`的對象都實現了「可接續」（thenable）接口。可接續對象實現了`.then()`方法，`Promise`對象就是可接續的。

一個promise被稱為已落實（settled），如果它要麼已履行（fulfilled）要麼已拒絕（rejected），而不再待定（pending）。`Promise`實例的`.then()`方法，接受一到二個實際參數，它們是作為處理器異步執行的回調函數，分別針對了這個promise的已履行和已拒絕情況；此方法返回一個新的promise，它決定（resolve）出其所調用處理器的返回值，或者在原來這個promise未被處理的情況下，仍決定出其已落實的值。`Promise`實例的`.catch()`方法，實際上就是置空針對已履行情況的回調函數，而只有針對已拒絕情況的回調函數的`.then()`方法。

`Promise()`構造子創建`Promise`對象，它主要用於包裝仍基於回調的API所提供的異步 (電腦編程)運算，要注意它只能通過`new`算子來構造：`new Promise(executor)`。`Promise()`構造子的實際參數叫做「執行器」（executor），它是由這個構造子同步執行的一個函數，它有可自行指定名字的兩個函數形式參數，比如指定為`resolveFunc`和`rejectFunc`，這兩個函數接受任何類型的單一實際參數。

`Promise()`構造子返回的`Promise`對象，在要麼`resolveFunc`函數要麼`rejectFunc`函數被調用之時，它就成為「已決定」（resolved）的。要注意如果在調用這兩個函數之一的時候，將另一個`Promise`對象作為實際參數傳遞給它，則這個`Promise`對象可以稱為已決定但仍未落實。在執行器中有任何錯誤拋出，都會導致這個promise成為已拒絕狀態，而返回值會被忽略。

`Promise`類提供四個靜態方法來實施異步任務 (計算)並發，其中的`Promise.allSettled()`方法，接受有多個promise的可迭代對象作為輸入，當所有輸入的promise都已落實之時，返回一個單一的已履行的`Promise`對象，它決定出描述每個輸入promise的結果的一個對象陣列；其中每個對象都有`status`屬性，它是字串`"fulfilled"`或者`"rejected"`；還有在`status`為`"fulfilled"`時出現的屬性`value`，或者在`status`為`"rejected"`時出現的屬性`reason`。

在下面例子中，全局`fetch()`方法，啟動從網路上取回一個資源的過程，並返回一旦響應可獲得就履行的一個promise；這個promise決定出表示對這個請求響應的一個`Response`對象，它只在遇到網路錯誤之時拒絕。`Response.text()`方法返回一個promise，它決定出這個響應的主體的一個文本表示。

```javascript
const urls = [
    'https://developer.mozilla.org/',
    'https://javascript.info/promise-api',
    'https://no-such-url'
];

const fetchPromises = urls.map((url) => fetch(url));

Promise.allSettled(fetchPromises)
.then((results) => { 
    results.forEach((result, num) => {
        if (result.status == "fulfilled") {
            if (result.value.ok) { 
                result.value.text()
                .then((data) => {
                    console.log(`${urls[num]}: ${data.length} bytes`);
                })
                .catch((err) => {
                    console.error(err);
                });
            } 
            else {
                console.log(`${urls[num]}: ${result.value.status}`);
            }
        }
        else if (result.status == "rejected") {
            console.error(`${urls[num]}: ${result.reason}`);
        }
    });
});
```

JavaScript是天然的單線程的，所以在給定時刻只有一個任務 (計算)在程序執行，但控制可以在不同的promise之間轉移，使得多個promise表現為並發執行。在JavaScript中並行執行只能通過分立的worker後台線程來完成。

同基於promise的代碼合作的一種更簡單的方式，是使用async/await關鍵字。在函數開始處增加`async`，使其成為異步函數，異步 (電腦編程)函數總是返回一個promise。在異步函數中，可以在對返回一個promise的函數的調用之前，使用`await`關鍵字；這使得代碼在這一點上等待直到這個promise已落實下來，然後在這一點上promise的已履行的值被當作返回值，而已拒絕的理由被作為例外拋出。可以使用`try...catch`塊進行例外處理，就如同這個代碼是同步的一樣。

## 實現列表

### 程式語言支持

下面列出支持future、promise和並發邏輯變量、數據流程變量或I-變量的語言，包括直接在語言中支持還有在標準庫中支持：

- ABCL/f
- Alice語言，支持future
- AmbientTalk，包含頭等的resolver和只讀promise
- C++，從C++11開始有std::future和std::promise
- Concurrent ML，僅限I-變量和M-變量
- Crystal語言
- Dart，使用Future/Completer類以及關鍵字`async`/`await`
- Elm，通過Task模塊
- Glasgow Haskell，僅限同步可變變量「MVars」
- Id語言，僅限I-結構和M-結構
- Io
- Java，通過Future或CompletableFuture
- JavaScript，始於ECMAScript 2015提供`Promise`對象，並且自從ECMAScript 2017可通過關鍵字`async`/`await`來使用
- Lucid，僅限作為串流的變量
- 一些Lisp
- Clojure
- MultiLisp
- Racket
- .NET，自.NET框架 4.0起通過TPL（任務並行庫）
- C#，自.NET框架 4.5起，通過關鍵字`async`/`await`
- Visual Basic，自從版本11，通過關鍵字`Async`/`Await`
- Kotlin，但是`kotlin.native.concurrent.Future`通常只在書寫本機運行代碼時使用
- Nim，使用`async`/`await`語法
- Oxygene語言
- Oz版本3
- Python，自從2011年版本3.2提供concurrent.futures模塊，這是由PEP 3148所提議，而2015年版本3.5增加了基於低層future的`asyncio`模塊，它採用高層`async`/`await`語法
- R，延遲計算的promise，仍然是單線程
- Raku
- Rust，通常經由`.await`完成
- Scala，通過scala.concurrent包
- Scheme，僅延遲求值
- Squeak Smalltalk
- Strand語言

還支持promise流水線的語言包括：

- E
- Joule語言

### 非標準庫的實現

- Blackbird
- Eager Future2
- lparallel
- PCall
- Boost library
- Dlib
- Qt
- Seastar
- Folly
- POCO C++ Libraries，ActiveResult
- 對於C#和其他.NET語言：
- Parallel Extensions庫
- GPars
- Promises/A+標準網站，有此標準的實現的列表
- Cujo.js的when.js，提供的promise符合Promises/A+ 1.1標準
- Dojo Toolkit，提供promise和Twisted風格Deferred
- MochiKit，受Twisted的Deferred的啟發
- jQuery的Deferred對象，基於了CommonJS Promises/A規定
- AngularJS
- Q，符合Promises/A+ 1.1標準
- RSVP.js，符合Promises/A+ 1.1標準
- Bluebird
- Google Closure工具的promise包，符合Promises/A+標準
- JDeferred，提供了與JQuery.Deferred對象類似的deferred-promise API和行為
- ParSeq，提供task-promise API，由LinkedIn維護，適用於異步流水線和分支
- MAFuture、RXPromise、ObjC-CollapsingFutures、PromiseKit、objc-promise、OAPromise
- Lazy模塊實現了懶惰的顯式future
- Future、Promises、Reflex
- React/Promise
- promise
- Twisted的Deferred
- future，實現可擴展的future API與懶惰和及早同步和（多核或分布式）異步future
- Promise gem
- libuv gem，實現promise
- Celluloid gem，實現future
- future-resource
- futures-rs
- Twitter的util庫
- 異步框架，實現C#風格的`async`/非阻塞`await`
- FutureKit，Apple的GCD（Grand Central Dispatch）實現版本
- FutureLib，純Swift 2庫實現的Scala風格的future和promise與TPL風格的取消
- Deferred，純Swift庫，受到OCaml的Deferred啟發
- BrightFutures
- tcl-promise

### 自行實現

future可以用協程或生成器實現，從而具有相同的求值策略（例如協同多任務或延遲求值）。

future還可以很容易地用通道實現：future是一個單元素的通道，而promise是一個發送到通道，實現future的過程。這允許future在支持通道（如CSP和Go）的並發程式語言中實現。由此產生的future是顯式的，因為它們必須通過從通道讀取而不是僅僅通過求值來獲取。

## 只讀視圖

在某些程式語言（如Oz、E和AmbientTalk）中，可以獲得推遲值的「只讀視圖」，允許在解決（resolve）出這個值之後通過它來讀取，但不允許通過它來解決這個值：

- 在Oz語言中，`

`運算符用於獲得只讀視圖。

- 在E語言和AmbientTalk中，推遲值由一對稱為「promise/resolver對」的值表示。promise表示只讀視圖，需要resolver來設置推遲值。
- 在C++11中，`std::future`提供了一個只讀視圖。該值通過使用`std::promise`直接設置，或使用`std::packaged_task`或`std::async`設置為函數調用的結果。
- 在Dojo Toolkit的1.5版本的Deferred API中，「僅限consumer的promise對象」表示只讀視圖。
- 在Alice語言中，future提供「只讀視圖」，而promise包含future和解決future的能力。
- 在.NET 4.0中，`System.Threading.Tasks.Task<T>`表示只讀視圖。解決值可以通過`System.Threading.Tasks.TaskCompletionSource<T>`來完成。

對只讀視圖的支持符合最小特權原則，因為它使得設置值的能力僅限於需要設置該值的主體。在同樣支持流水線的系統中，異步消息（具有結果）的發送方接收結果的只讀promise，消息的目標接收resolver。

## 有關結構

「future」是事件同步原語的特例，它只能完成一次。通常，事件可以重置為初始的空狀態，因此可以根據需要多次完成。

「I-var」是具有下面定義的阻塞語義的future。它起源於Id語言中包含I-var的「I-structure」數據結構。可以使用不同值多次設置的有關同步構造稱為「M-var」。M-var支持`take`（採取）或`put`（放置）當前值的原子性操作，這裡採取這個值還將M-var設置回其初始的「空」狀態。

「並發邏輯變量」與future類似，但是通過合一更新，與邏輯編程中的「邏輯變量」相同。因此，它可以多次綁定到可合一的值，但不能設置回到空或未解決狀態。Oz的數據流變量充當並發邏輯變量，並且還具有上面提到的阻塞語義。

「並發約束變量」是並發邏輯變量的一般化，以支持約束邏輯編程：約束可以多次「縮小」，表示可能值的較小集合。通常，有一種方法可以指定每當約束進一步縮小時應該運行的thunk；這是支持「約束傳播」所必需的。

## 隱式與顯式future

對future的使用可以是「隱式」的，任何對future的使用都會自動獲得它的值，它就像是普通的引用一樣；也可以是「顯式」的，使用者必須調用函數來獲取值，例如Java中的Future或CompletableFuture的`get`方法。獲得一個顯式的future的值可以稱為「刺激」（stinging）或「強迫」（forcing）。顯式future可以作為庫來實現，而隱式future則通常作為語言的一部分來實現。

最初的Baker和Hewitt論文描述了隱式future，它們在演員模型和純面向對象程式語言（如Smalltalk）中自然得到支持。Friedman和Wise的論文只描述了顯式的future，可能反映了在老舊硬體上有效實施隱式future的困難。難點在於老舊硬體不能處理原始數據類型（如整數）的future。例如，add指令不會處理`3 + future factorial(100000)`。在純演員模型或面向對象語言中，這個問題可以通過向`future factorial(100000)`發送消息`+[3]`來解決，它要求future自己加`3`並返回結果。請注意，無論`factorial(100000)`何時完成計算，消息傳遞方法都可以工作，而且不需要任何「刺激」或「強迫」。

## 阻塞與非阻塞語義

如果future的值是異步訪問的，例如通過向它發送消息，或者通過使用類似於E語言中的`when`的構造顯式地等待它，那麼在消息可以被接收或等待完成之前，推遲直到future得到解決（resolve）是沒有任何困難的。這是在純異步系統（如純演員語言）中唯一需要考慮的情況。

然而，在某些系統中，還可能嘗試「立即」或「同步」訪問future的值。這樣的話就需要做出一個設計選擇：

- 訪問可能會阻塞當前線程或進程，直到future得到解決（可以具有超時）。這是Oz語言中「數據流變量」的語義。
- 嘗試的同步訪問總是會引發信號指示錯誤，例如拋出異常。這是E語言中遠程promise的語義。
- 潛在的，如果future已經解決，則訪問可能成功，但如果未解決，則發出信號指示錯誤。這樣做的缺點是引入了不確定性和潛在的競爭條件，這似乎是一種不常見的設計選擇。

作為第一種可能性的示例，在C++11中，需要future值的線程可以通過調用`wait()`或`get()`成員函數來阻塞，直到它可獲得為止。還可以使用`wait_for()`或`wait_until()`成員函數指定等待超時，以避免無限期阻塞。如果future對`std::async`的調用，那麼阻塞等待（沒有超時）可能導致函數的同步調用以計算等待線程上的結果。

## promise流水線

在分布式系統中使用推遲值可以顯著地減少傳輸延遲。例如，指稱推遲值的promise，成就了「promise流水線」，就像在E語言和Joule語言語言中實現的那樣，它在Argus語言中稱為「call-stream」。

考慮一個涉及常規遠程過程調用的表達式，例如：

```
 t3 := (x.a()).c(y.b())
```

可以展開為

```
 t1 := x.a();
 t2 := y.b();
 t3 := t1.c(t2);
```

每個語句需要發送一條消息，並在下一個語句可以繼續之前收到一個答覆。例如，假設`x`、`y`、`t1`和`t2`都位於同一台遠程機器上。在這種情況下，在開始執行第三條語句之前，必須對該機器進行兩次完整的網路往返。然後，第三條語句將引起另一個到同一個遠程機器的往返。

上面的表達式可以使用E語言的語法寫為：

```
 t3 := (x <- a()) <- c(y <- b())
```

其中`x <- a()`表示將消息`a()`異步發送給`x`。它可以展開為：

```
 t1 := x <- a();
 t2 := y <- b();
 t3 := t1 <- c(t2);
```

所有三個變量都會立即為其結果分配promise，執行過程將繼續進行到後面的語句。之後嘗試解決`t3`的值可能會導致傳輸延遲；但是，流水線操作可以減少所需的往返次數。如果與前面的示例一樣，`x`、`y`、`t1`和`t2`都位於相同的遠程機器上，則流水線實現可以用一次往返來計算`t3`，不必用三次。由於所有三條消息都指向同一遠程電腦上的對象，因此只需要發送一個請求，只需要接收一個包含結果的響應。另請注意，即使`t1`和`t2`位於不同機器上，或者位於與`x`或`y`不同的機器上，發送`t1 <- c(t2)`也不會阻塞。

promise流水線應與並行異步消息傳遞區分開來。在支持並行消息傳遞但不支持流水線操作的系統中，上面示例中的消息發送`x <- a()`和`y <- b()`可以並行進行，但發送`t1 <- c(t2)`將不得不等到`t1`和`t2`都被接收，即使`x`、`y`、`t1`和`t2`在同一個遠程機器上。在涉及許多消息的更複雜情況下，流水線的相對傳輸延遲優勢變得更大。

promise流水線操作也不應與演員系統中的流水線式消息處理相混淆，在這種系統中，演員可以在完成當前消息的處理之前，指定並開始執行下一個消息的行為。

## 有特定線程的future

某些語言比如Alice語言，定義的future可以關聯著計算這個future值的特定線程。這種計算可以通過`spawn exp`，在創建future時及早地開始；或者通過`lazy exp`，在首次需要其值時懶惰地開始。在延遲計算的意義上，懶惰的future類似於thunk。

Alice ML還支持可由任何線程解決的future，並稱謂它們為「promised future」。這裡的promise是給future的顯式把柄（handle），它通過多態庫函數`Promise.promise`來創建，所有promise都關聯的一個future，創建一個新promise也就創建了一個新鮮的future；這個future通過`Promise.future`來提取，並且通過顯式的應用`Promise.fulfill`於對應的promise來消除，即在全局中將這個future替代為一個值。Alice ML不支持promise流水線，轉而對於future，包括關聯著promise的future，流水線是自然而然地發生的。

在沒有特定線程的future（如Alice ML所提供的）中，通過在創建這個future的同時創建一個計算這個值的線程，可以直接實現及早求值的有特定線程的future。在這種情況下，最好將只讀視圖返回給客戶，以便僅讓新創建的線程能夠解決這個future。

要在沒有特定線程的future中，實現隱式惰性的有特定線程的future，需要一種機制來確定何時首次需要future的值（例如，Oz中的`WaitNeeded`構造）。

如果所有值都是對象，那麼有實現透明轉發對象的能力就足夠了，因為發送給轉發器的首條消息表明需要future的值。

假定系統支持消息傳遞，在有特定線程的future中，通過讓解決線程向future自己的線程發送消息，可以實現沒有特定線程的future。然而這可能被視為不必要的複雜性。在基於線程的程式語言中，最具表現力的方法似乎是提供一種混合：沒有特定線程的future、只讀視圖、以及要麼有`WaitNeeded`構造要麼支持透明轉發。

## 傳future調用

就求值策略而言，「傳future調用」是非確定性的：future的值將在創建future和使用其值之間的某個時間進行求值，但確切的時間不確定的，一次運行和另一次運行的求值時間會不一樣。計算可以在創建future時開始（及早求值），或者僅在實際需要值時開始（懶惰求值），並且可以在中途暫停，或在一次運行中執行。一旦future被賦值，它就不會在訪問future的時候重新計算；這就像傳需求調用時使用的記憶化。

「懶惰」future是確定性的具有惰性求值語義的future：future值的計算在首次需要時開始，與傳需要調用一樣。懶惰future使用在求值策略默認不是懶惰求值的語言中。例如，在C++11中，可以通過將`std::launch::deferred`啟動策略傳遞給`std::async`以及計算值的函數來創建這種惰性future。

## 演員模型中的future語義

在演員模型中，形式為`future <Expression>`的表達式，以它對具有環境E和客戶C的`Eval`消息的響應方式來定義：future表達式通過向客戶C發送新創建的演員F（計算`<Expression>`的響應的代理）作為返回值來響應`Eval`消息，與之並發的向`<Expression>`發送具有環境E和客戶F的`Eval`消息。F的默認行為如下：

- 當F收到請求R時，它會檢查是否已經收到來自求值`<Expression>`的響應（可以是返回值或拋出異常），處理過程如下所示：
- 如果它已經有了響應V，那麼
- 如果V是返回值，那麼向它發送請求R。
- 如果V是一個異常，那麼就把這個異常拋給請求R的客戶。
- 如果它還沒有響應，那麼將R存儲在F內的請求隊列中。
- 當F接收到來自求值`<Expression>`的響應V時，那麼將V存儲在F中，並且
- 如果V是返回值，那麼將所有排隊的請求發送到V。
- 如果V是一個異常，那麼就會把這個異常拋出給每個排隊請求的客戶。

但是，一些future可以通過特殊方式處理請求以提供更大的並行性。例如，表達式`1 + future factorial(n)`可以創建一個新的future，其行為類似於數字`1+factorial(n)`。這個技巧並不總是有效。例如，以下條件表達式：

`if m>future factorial(n) then print("bigger") else print("smaller")`

會掛起，直到`factorial(n)`這個future已回應詢問`m`是否大於其自身的請求。

## 外部連結

- Concurrency patterns presentation given at scaleconf
- Future Value and Promise Pipelining at the Portland Pattern Repository
- Easy Threading with Futures in Python