web-dev-qa-db-ja.com

Clojureの先物と約束はどのように異なりますか?

先物とプロミスの両方が値を計算するまでブロックされるので、それらの違いは何ですか?

87
Yazz.com

Clojureの用語で回答すると、以下は Sean Devlinのスクリーンキャスト の例です。

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

Promiseでは、後の計算で選択した値を明示的に提供していることに注意してください(:fred この場合)。一方、未来は創造された場所と同じ場所で消費されています。 some-exprはおそらくバックグラウンドで起動され、タンデムで(最終的には)計算されますが、アクセスされるまでに評価されないままの場合、スレッドが使用可能になるまでブロックされます。


編集して追加

約束と未来をさらに区別するために、次のことに注意してください。

約束する

  1. promiseを作成します。そのpromiseオブジェクトは任意のスレッドに渡すことができます。
  2. 計算を続けます。これらは、副作用、データのダウンロード、ユーザー入力、データベースアクセス、その他の約束など、非常に複雑な計算です。コードは、どのプログラムでもメインラインコードとよく似ています。
  3. 完了したら、結果をそのpromiseオブジェクトにdeliverできます。
  4. 計算が完了する前に約束をderefしようとするアイテムは、完了するまでブロックされます。完了してプロミスをdeliveredすると、プロミスはブロックされなくなります。

未来

  1. あなたはあなたの未来を創造します。あなたの未来の一部は計算式です。
  2. フューチャーは同時に実行される場合とされない場合があります。おそらくプールからスレッドを割り当てることができます。待つだけで何もできません。あなたの観点からはわかりません
  3. ある時点で、あなた(または別のスレッド)が未来をderefsします。計算がすでに完了している場合は、その結果を取得します。まだ完了していない場合は、完了するまでブロックします。 (おそらくまだ起動していない場合、derefingは実行を開始することを意味しますが、これも保証されません。)

あなたができます将来、式はプロミスの作成に続くコードと同じくらい複雑になりますが、望ましいことは疑わしいです。つまり、futureはバックグラウンドで実行可能な迅速な計算に適していますが、promiseは大きくて複雑な実行パスに適しています。あまりにも、約束は、利用可能な計算の点で、もう少し柔軟で、約束の作成者が作業を行い、別のスレッドが収穫を得ることに向けられているように見えます。 Futuresは、(醜くてエラーが発生しやすいオーバーヘッドなしで)スレッドを自動的に開始し、ユーザー(元のスレッド)が結果を必要とするまで他のことを続行することに重点を置いています。

FutureとPromiseはどちらも、プロデューサーからコンシューマーに非同期計算の結果を通信するメカニズムです。

Futureの場合、計算はFutureの作成時に定義され、非同期実行が開始されます "ASAP 」また、非同期計算を生成する方法を「認識」しています。

約束の場合計算、その開始時間および[可能な]非同期呼び出しは、配信メカニズムから切り離されています。 computationの結果が利用可能な場合、プロデューサーはdeliverを明示的に呼び出す必要があります。これは、プロデューサーがを制御することも意味します結果が利用可能になります。

For Promises Clojureは、同じオブジェクト(promise呼び出しの結果)を使用して(deliver)を生成し、消費する(derefcomputationの結果。これらは2つの非常に異なる機能であり、そのように扱う必要があります。

24
Dimagog

すでに優れた答えがあるので、「使い方」の要約を追加するだけです。

両方

Promiseまたはfutureを作成すると、参照がすぐに返されます。この参照は、計算結果が他のスレッドによって提供されるまで@/derefでブロックされます。

将来

Futureを作成するときに、実行する同期ジョブを指定します。専用の無制限のプールからスレッドで実行されます。

約束

Promiseを作成するときに、引数を指定しません。参照は、結果をdeliverにする他の「ユーザー」スレッドに渡す必要があります。

3