跳至內容

Future佮promise

出自Taiwan Tongues 台語維基
這是此頁批准,以及是最近的修訂。

佇電腦科學當中,futurepromisedelaydeferred是指用佇某寡並行程式語言中同步程式執行的構造。因為某寡計算(或者是網路咧請求)猶未結束,咱需要一个物件來代理這个未知的結果,就按呢有了上述這个構造(future、promise 等)。

「 promise」一詞由丹尼爾 ・ 福瑞得曼和 David Wise 佇一九七六年提出, Peter Hibbard 彼个稱為「eventual」。 一九七七年 Henry Baker 和 Carl Hewitt 佇一篇論文中介紹一个類似的概念「future」。

術語「future」、「 promise」、「 delay」和「deferred」通常會當相換使用,而且「future」佮「promise」之間的使用差異,阮就共佇下跤咧討論。具體來講,做區分使用的時陣,future 是變數的「唯讀」預留位置視圖,而且 promise 是會當寫單賦值容器,用於設定 future 的值。值得注意的是,無需要指定會當設定其值的 promise 就會當定義 future,並且無仝款的 promise 會當設定仝一个 future 的值,就算講對予定的 future 干焦會當執行一擺。佇其他的情形下,future 和 promise 是做伙建立的,並且互相關聯:future 是值,promise 是設定值的函式—— 本質上是非同步函式(promise)的倒轉去值(future)。 設定 future 的值的過程嘛講做「resolve」(解析)、「fulfil」(實現)抑是「bind」(結束)伊。

應用

future 和 promise 起源於函式語言程式設計佮相關的範例(如邏輯編程), 目的是將值(future)佮其計算方式(promise)分離,對這來允准更加靈活地進行計算,特別是通過並列化。後來,伊佇分散式計算中得著應用,減少通信往回的延遲。閣尾仔,伊變閣較有效矣,因為伊會當直接風格編寫非同步程式,毋是以連紲傳遞風格的方式。

隱式佮顯式

著 future 的使用可能是「若隱式的」(任何著 future 的使用攏會去主動著伊的值得,伊就佮普通參照仝款)抑是「顯式的」(使用者著愛呼叫函式來取得值,比如講 Java 中的 Future 抑是 CompletableFuture 的 ` get ` 方法)。 得著一个顯式的 future 的值會當講「stinging」抑是「forcing」。 顯式 future 有法度做為庫來實現,若隱式 future 則通常做語言的一部份來共實現。

上代先的 Baker 和 Hewitt 論文描述了隱式 future,𪜶佇演員模型佮純物件導向程式設計語言(如 Smalltalk)自然得著支援。Friedman 和 Wise 的論文干焦描述顯式的 future,可能反映佇老舊硬體頂懸有效實施隱式 future 的困難。因為是老舊硬體袂當處理原始的資料類型(如整數)的 future。比如講,add 指令講袂曉處理 ` 三 + future factorial ( 十曉 ) `。佇咧純演員模型抑是物件導向語言內底,這个問題會當通過傳送 ` future factorial ( 十曉 ) ` 訊息 ` + [三] `,伊要求 future 家己加 ` 三 ` 閣倒轉來結果。請注意,無論 ` factorial ( 十曉 ) ` 當時完成計算,訊息傳遞方法攏會當做工課,而且無需要任何 sting 抑是 force。

promise 管線

佇分散式系統當中使用 future 會當顯示塗跤減少延遲。比如講,future 予「promise 管線」成做是可能,就親像佇咧 E 語言佮 Joule 語言內底實現的彼款的,佇咧 Argus 語言內底這嘛予人叫做是「call-stream」。

考慮一个牽涉定定規遠端程序呼叫的表達式,比如講:

` ` ` t 三   :=( x . a ( ) ) . c ( y . b ( ) ) ` ` `

會當擴充做

` ` ` t 一   :=x . a ( ) ; t 二   :=y . b ( ) ; t 三   :=t 一 . c ( t 二 ) ; ` ` `

逐个語句需要傳送一條訊息,而且佇後一个語句會當繼續進前收著一个答覆。比如講,準講 ` x `、` y `、` t 一 ` 和 ` t 二 ` 攏佇仝一台遠端的機器頂懸。佇這个情形下,佇咧開始執行第三條語句進前,必須對該機器做兩改完整的網路去倒轉來。然後,第三條語句將引起另外一个到仝一个遠端機器的往回。

使用 future,頂懸的表達式會當寫做

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

會當擴充做

` ` ` t 一   :=x <-a ( ) ; t 二   :=y <-b ( ) ; t 三   :=t 一 <-c ( t 二 ) ; ` ` `

遮有用的語法就是 E 語言的語法,其中 ` x <-a ( ) ` 表示會訊息 ` a ( ) ` 非同步傳送予 ` x `。所有三个變數攏會隨共結果分配 future,執行過程會繼續進行到後壁的語句。了後試看覓影決 ` t 三 ` 的值可能會致使延遲;猶毋過,管線操作會當減少所需要的往回數。你若相頭前的範例仝款,` x `、` y `、` t 一 ` 和 ` t 二 ` 攏佇仝款的遠端機器頂懸,則管線實現會當用一改往回來計算 ` t 三 `,毋免講用三擺。因為所有三條訊息攏指向仝一遠端電腦上的物件,所以只需要傳送一个請求,只需要接收一个包含結果的回應。另外閣注意,就算 ` t 一 ` 和 ` t 二 ` 佇咧無仝機器上,抑是佮位佇咧 ` x ` 抑是 ` y ` 無仝的機器上,傳送 ` t 一 <-c ( t 二 ) ` 嘛袂窒得。

promise 管線應該佮列非同步的訊息傳達區分開。支援並列訊息傳達毋過無支援管線操作的系統中,頂懸的範例內底的訊息傳送 ` x <-a ( ) ` 和 ` y <-b ( ) ` 會當並列進行,但是傳送 ` t 一 <-c ( t 二 ) ` 將不得不等到 ` t 一 ` 和 ` t 二 ` 攏予人接收去,就算 ` x `、` y `、` t 一 ` 和 ` t 二 ` 佇仝一个遠端的機器頂懸。咧牽涉真濟訊息的閣較複雜情況下,管線的相對延延優勢變閣較大。

promise 管線操作嘛無應該佮演員系統中的管線訊息處理相透濫,佇咧這種系統內底,會當演員佇完成做前訊息的處理進前指定並開始執行後一个訊息的行為。

唯讀視圖

佇某一寡程式語言(如 Oz \ E 和 AmbientTalk)中,會當得著未來的「唯讀視圖」,該視圖允准佇咧 resolve 後讀其價值,但無允准 resolve 伊:

  • 佇咧 Oz 語言內底,

! ! 運算子用佇得著唯讀視圖

  • 佇咧 E 語言佮 AmbientTalk 中,future 由一對稱為「promise / resolver 著」的值表示。promise 表示唯讀視圖,需要 resolver 來設定 future 的值。
  • 佇咧 C + + 十一中,` std : : future ` 提供一个唯讀視圖。該值通過使用 ` std : : promise ` 直接設定講,抑是使用 ` std : : packaged _ task ` 抑是 ` std : : async ` 設定做函式呼的結果。
  • 佇咧 Dojo Toolkit 的一孵五版本的 Deferred API 中,「 干焦限 consumer 的 promise 東西」表示唯讀視圖。
  • 佇咧 Alice ML 中,future 提供「唯讀視圖」,而且 promise 包含 future 和 resolve future 的能力
  • 佇咧 . NET 四淋零中,` System . Threading . Tasks . Task < T > ` 表示唯讀視圖。解析值會當通過 ` System . Threading . Tasks . TaskCompletionSource < T > ` 來完成。

對唯讀視圖的支援符合上小特權原則,因為伊允准會值設定為干焦限定需要設定這个主體。佇仝款支援管線的系統內底,非同步訊息的傳送方(包括結果)接收結果的唯讀是承諾 promise,訊息的目標接收 resolver。

針對特定執行緒的 future

某一寡語言(如 Alice ML)定義矣佮計算 future 值的特定執行緒相關聯的 future。這種計算會當佇建立 future 的時陣早開始,抑是講佇咧第一改需要其值時間貧惰地開始。佇延遲計算的意義,貧惰的 future 類似 thunk。

Alice ML 閣支援會當由任何執行解決的 future,並呼叫遮的「promise」。「promise」的這種使用無仝文所述的佇 E 語言內底的使用。佇咧 Alice 中,promise 毋是唯讀視圖,並且無支援 promise 管線操作。相反,對於 future 未來,包括佮 promise 相關的 future,管線是自然的毋過發生的。

阻窒佮非常的窒語意

若是 future 的值是非同步存取的,比如講通過向伊傳送的訊息,抑是通過使用類似於 E 語言內底的 ` when ` 的構造顯式的等待伊,若按呢咧收著訊息抑是完成等待進前,捒甲遲到 future 得著 resolve 無任何的困難。這是佇咧純非同步系統(純演員的語言)唯一需要考慮的情形。

毋過,佇咧某一寡系統內底,閣有可能按呢試「隨」抑是「仝步」存取 future 的值。若按呢就需要做出一个設計選擇:

  • 存取權限可能會窒起來進前執行緒抑是行程,一直到 future 得著 resolve(可能需要超時間)。 這是 Oz 語言內底「資料流變數」的語意。
  • 試看覓仝步的存取總是會發出錯誤訊號,譬如講跋無異常。這是 E 語言中遠端 promise 的語意。
  • 若是 future 已經 resolve,是存取可能成功,猶毋過若無 resolve,是發出錯誤訊號。按呢做的缺點是引入了無確定性佮藏佇咧的競爭條件,這敢若是一種無四常的設計選擇。

做第一種可能性的範例,佇咧 C + + 十一中,需要 future 值的執行緒會當通過呼叫 ` wait ( ) ` 抑是 ` get ( ) ` 成員函式來阻礙,一直到可以為止。你猶閣會使用 ` wait _ for ( ) ` 抑是 ` wait _ until ( ) ` 成員函式指定等待搜時,以避免無限期的阻塞。若是 future 著 ` std : : async ` 的呼叫,遐爾仔窒等待(無超時間)可能致使函式的同步呼叫以計算等待執行緒上的結果。

相關結構

「 future」是 Event(仝步原語)的特例,干焦會當完成一改。通常,event 會當重新做初空的狀態,因此會當根據需要濟擺完成。

「 I-var」(我若是語言 Id 中)是有頂懸定義的阻塞語意的 future。「I-structure」是包括 I-var 的資料結構。會使使用無仝值濟改設定的相關同步構造叫做「M-var」。 M-var 支援「採用」抑是「囥」當前值的原子咧操作,其中取經過閣共 M-var 就共設定講轉來其初「空」狀態。

「 閣再行邏輯變數」佮 future 類似,但是通過合一更新,佮邏輯編程當中的「邏輯變數」相仝。所以,伊會當多擺結合甲會合的值,啊袂當去設定回空抑是 unresolved 狀態。Oz 的資料流變數充當閣再行邏輯變數,並且閣有頂懸講著的阻塞語意。

「 並行約束變數」是並行邏輯變數的一般化,用支援約束邏輯編程:約束會使幾若改「縮小」,表示講可能值較細个集合。通常,有一種方法會當指定逐當約束進一步縮點鐘應該執行的 hunk;這是支援「約束傳播」一定愛的。

無仝款的形式 future 的表達能力之間的關係

通過佇咧建立 future 的同時建立一个計算值的執行緒,會當佇非執行緒特有的 promise 中直接實現及早求值的執行緒特有的 future。佇這个情形下,future 將唯讀視圖返轉予客戶捀,通好干焦予新建立的執行緒會當解決這个 future。


欲佇非執行緒特有的 promise 中實現隱式延遲執行緒特有的 promise(比如講由 Alice ML 提供), 需要一種機制來確定當時首先需要 future 的值(比如講,Oz 中的 ` WaitNeeded ` 構造)。 若所有值攏是物件,遐爾實現透明轉發物件的能力就夠額矣,因為傳送予轉發器的頭一條訊息表明需要 future 的值。

假定系統支援訊息傳遞,通過予 resolve 執行緒向 future 家己的執行緒傳送的訊息,會使線頂較特有的 future 中實現非執行緒特有的 future。猶毋過,這會當予人看做無一个複雜性。佇基於執行緒的程式語言中,上有表現力的方法敢若是提供非執行緒特有的 future,唯讀視圖以及「WaitNeeded」構造抑是支援透明轉發的混合。

求值策略

future 的求值策略(會當講「傳 future 搧叫」)是非確定性的:future 的值將佇咧建立 future 佮使用其值之間的某一个時間進行求值,毋過確定的時間無確定的,一擺執行佮另外一擺執行的求值時間會無仝款。算講會當佇建立 future 時開始(佮早求值), 抑是佇實際需要值的時陣開始(貧惰求值), 而且會使佇中途暫停,抑是講佇一擺執行中執行。一旦 future 被賦值,伊就袂閣佇存取 future 的時陣重新計算;這就像傳需求呼叫時使用的記持化。

貧惰 future是確定性有慢性求值評估語意的 future:future 值的計算佇第一改需要時間來開始,佮傳需要呼叫仝款。貧惰 future 佇求值策略預設毋是貧惰求值的語言內底使用。比如講,佇咧 C + + 十一中,會當通過共 ` std : : launch : : deferred ` 啟動策略傳遞予 ` std : : async ` 以及計算值的函式來建立這種慢性 future。

演員模型當中的 future 語意

佇演員模型當中,形式做 ` future < Expression > ` 的表達式由伊對 ` Eval ` 訊息(環境為著 E,客戶為 C)的回應方式定義:future 表達式通過向客戶 C 傳送新建立的演員來回應 ` Eval ` 訊息 F(計算 ` < Expression > ` 回應的代理)作為倒轉來值,「 佮這个同時 " 向 ` < Expression > ` 傳送環境 E 佮客戶 C 的 ` Eval ` 訊息。F 的預設行為如下:

  • 當 F 收著請求 R 時,伊會通過評估 ` < Expression > ` 繼續檢查伊敢是已經收著回應(會當是返回值抑是擲異常), 如下所示:

一 . 若準講伊已經有回應 V,遐爾

  • 若是 V 是倒轉去,著愛傳送予請求 R .
  • 若是 V 是一个各樣,遐爾仔就會共這个異常拋予請求 R 的客戶。

二 . 伊若猶未回應,著 R 儉佇咧 F 內底的要求在列中。

  • 當 F 對評估 ` < Expression > ` 接著回應 V 時,著 V 儉佇咧 F 中
  • 若是 V 是倒轉去,則將 V 傳送到所有排隊的請求 .
  • 若是 V 是一个各樣,遐爾仔就會共這个異常擲擲予逐个排隊請求的客戶。

猶毋過,一寡仔 future 會當通過特殊方式處理請求以提供閣較大的並列性。比如講,表達式 ` 一 + future factorial ( n ) ` 會當建立一个新的 future,其行為類似是數字 ` 一 + factorial ( n ) `。這个技巧並無總是有效。比如講,以下的條件表達式:


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

會掛起去,一直到 ` factorial ( n ) ` 這乎 future 已經回應問 ` m ` 敢有啥物款大於咱有家己的要求。

歷史

「 future」佮「promise」構造首先佇諸如 MultiLisp 和 Act 一等等的程式語言內底實現。佇閣有行邏輯編程語言當中使用邏輯變數進行通批非常的類似 future。這个開始於著「Prolog with Freeze」和「IC Prolog」,也成做真正的並行原語,包括關係語言、Concurrent Prolog、守衛霍恩子句(GHC)、 Parlog、Strand、Vulcan、Janus、Oz-Mozart、Flow Java 和 Alice ML。來自資料流程式語言的單一賦值「I-var」,源自 Id 並包括佇 Reppy 的「Concurrent ML」中,非常的類似而且也會使邏輯變數。

promise 管線技術(使用 future 來克服延遲)是 Barbara Liskov 和 Liuba Shrira 佇一九八八年發明的,由 Mark S . Miller、Dean Tribble 和 Rob Jellinghaus 佇大約一九八九年的 Xanadu 專案內底獨立發明。

「 promise」一詞是由 Liskov 和 Shrira 創造的,就算講𪜶通過名稱「call-stream」參照管線機制,這馬足少咧使用伊。

Liskov 和 Shrira 的論文中描述的設計以及 Xanadu 中的 promise 管線的實現攏有一个限制,即 promise 值毋是一等的:一个參數,抑是一个 call 抑是 send 倒轉來的值袂使直接成做一个 promise(所以頭前予出的 promise 管線的例,伊使用一个傳送的結果成做另外一个傳送的參數的承諾,佇咧 call-stream 設計抑是 Xanadu 實現中袂使直接表達)。 敢若 promise 和 call-stream 毋捌佇咧 Argus 任何公開發佈中實現,Liskov 和 Shrira 論文中使用的程式語言。Argus 的開發佇一九八八年左右停止矣。Xanadu 實現的 promise 管線干焦佇一九九九年 Udanax Gold 的原始碼發布的時才公開發布,而且佇任何已經發布的文件內底攏無解說過。Joule 和 E 的後續實現支援完全一等的 promise 和 resolver。

一寡較早的演員語言,包括講 Act 系列,支援並列訊息傳遞佮管線訊息處理,毋過無支援 promise 管線。(雖然技術上會當佇前兩个中實現最後一个功能,毋過無證據表明 Act 語言按呢行喔。)

二空空空年了後,因為訊息傳遞的請求-回應模型,future 和 promise 佇咧使用者介面回應佮 web 開發內底的應用重新引起了人的興趣。這馬有幾種主流的語言著 future 和 promise 攏有語言支援,上出名的是 Java 五中的 ` FutureTask `(二空空四年公佈)以及 . NET 四配五中的 ` async ` 和 ` await ` 結構(二空一空年發佈,二空一二年發佈)足大的程度上受著 F # 的「非同步工作的流程」(會當追溯到二空空七年)的啟發。隨後去予其他的語言採用,特別是 Dart(二千空一十四), Python(二千空一十五), Hack(HHVM)以及 ECMAScript 七(JavaScript)、 Scala 和 C + + 的草案。

實現列表

支援 future、promise、閣再行邏輯變數、資料流變數抑是 I-vars 的語言,無論是通過直接語言支援猶是佇標準庫內底,包括講:

閣支援 promise 管線的語言套件括:

是毋是標準庫的 future 實現:

協程

future 會當用協程抑是生成器實現,對而且產生相仝的評估這个策略(比如講,協同濟工抑是延遲評估)。

巷路

future 會足簡單會使用通道實現:future 是一个單元素的巷路,而且 promise 是一个傳送到通道,實現 future 的過程。這允准 future 咧支援巷路(如 CSP 和 Go)並行程式語言中實現。由此產生的 future 是顯式的,因為𪜶著愛通過對通道讀取毋是干焦通過評估來取得。

參見

  • 纖程
  • Futex

參考資料

外部連結

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