進階並行與非同步

未來與承諾(futures and promises)

在忙碌的咖啡店點杯咖啡,你會拿到一個呼叫器。咖啡還沒好,但這個呼叫器是個真實、握得住的憑證,說著「一杯咖啡將會送到這裡」。你可以把它收進口袋去做別的事;它響了,你就去取飲料。未來(future)就是程式裡的這個呼叫器:一個指向「尚不存在、但稍後會被填入」之值的把手。承諾(promise)則是泡咖啡那方握著的另一半:用來把值(或錯誤)送進那個未來的寫入端。

在機制上,一個未來和一個承諾共用一塊稱為共享狀態的記憶體。它裝著三樣東西:一個放結果的槽、一個「就緒/未就緒」旗標,和一份等候者名單。生產者握著承諾;工作完成時,它呼叫類似 promise.set_value(x) 的東西,把 x 寫進共享狀態、翻轉旗標、喚醒所有等候者。消費者握著未來;呼叫 future.get() 時,若已就緒就立刻回傳 x,否則就阻塞,直到承諾把它填好。關鍵在於兩者被拆開,使生產者與消費者可以跑在不同執行緒、在時間上解耦——消費者甚至可以在值被算出來之前就先要它。

未來之所以重要,是因為它給「正在進行中的結果」一個名字,於是你能在它完成之前就到處傳遞它、儲存它、組合它。這正是 async/await 與延續所建立其上的地基。兩個誠實的區分:未來是唯讀的(你去等待它),承諾是只寫一次的(你恰好兌現它一次)。而未來有兩種風味——急切式(C++ 的 std::future、JavaScript 的 Promise),其工作已經在跑;以及惰性式(Rust 的 Future),它在執行器去輪詢它之前什麼都不做。把這兩者搞混是 Rust 初學者的經典陷阱:一個沒被等待的 Rust future,只是一個永遠不會執行的值。

C++:std::promise<int> p; std::future<int> f = p.get_future(); std::thread([&]{ p.set_value(42); }).detach(); int x = f.get(); // 阻塞直到 42 送達。承諾負責寫、未來負責讀,共享狀態把兩者連起來。

一份共享狀態、兩個把手:承諾是寫入端,未來是讀取端。

命名並不一致:JavaScript 的 Promise 其實是多數語言所謂的 future(讀取側)。而 Rust 的 future 是惰性的——在被執行器輪詢之前它什麼都不跑;急切的 C++ std::future 則早已在執行。別假設只有一種模型。

又称
future / promisedeferred value期約承諾