約束と未来は補完的な概念です。Futureは、将来いつか取得される値であり、そのイベントが発生したときに、それを使って何かを行うことができます。したがって、それは計算の読み取りまたは出力のエンドポイントです-値を取得するものです。
約束は、類推により、計算の書き込み側です。計算の結果を置く場所であるプロミスを作成し、そのプロミスから、プロミスに入れられた結果を読み取るために使用されるフューチャーを取得します。失敗または成功によってプロミスを完了すると、関連するフューチャーに関連付けられていたすべての動作がトリガーされます。
あなたの最初の質問については、どのようにそれは約束のpに対して、我々が持っていることができますp.future == p
。これは単一アイテムバッファのように想像できます。最初は空のコンテナで、あとで1つの値を格納して、そのコンテンツが永久に変わるようにすることができます。さて、あなたの視点に応じて、これは約束と未来の両方です。バッファに値を書き込もうとする人にとっては約束です。その値がバッファーに入れられるのを待つ人にとっては未来です。
具体的には、ScalaコンカレントAPIの場合、ここのPromiseトレイトを見ると、Promiseコンパニオンオブジェクトのメソッドがどのように実装されているかがわかります。
object Promise {
/** Creates a promise object which can be completed with a value.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def apply[T](): Promise[T] = new impl.Promise.DefaultPromise[T]()
/** Creates an already completed Promise with the specified exception.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def failed[T](exception: Throwable): Promise[T] = new impl.Promise.KeptPromise[T](Failure(exception))
/** Creates an already completed Promise with the specified result.
*
* @tparam T the type of the value in the promise
* @return the newly created `Promise` object
*/
def successful[T](result: T): Promise[T] = new impl.Promise.KeptPromise[T](Success(result))
}
現在、Promise、DefaultPromise、KeptPromiseの実装はここにあります。これらは両方とも、たまたま同じ名前を持つ基本の小さな特性を拡張しますが、別のパッケージにあります。
private[concurrent] trait Promise[T] extends scala.concurrent.Promise[T] with scala.concurrent.Future[T] {
def future: this.type = this
}
だからあなたは彼らが何を意味するかを見ることができますp.future == p
。
DefaultPromise
上記で参照していたバッファですが、KeptPromise
作成時の値が入力されたバッファです。
あなたの例に関しては、そこで使用する将来のブロックは、実際には舞台裏での約束を作成します。定義で見てみましょうfuture
で、ここで:
def future[T](body: =>T)(implicit execctx: ExecutionContext): Future[T] = Future[T](body)
メソッドのチェーンに従うことで、最終的にはimpl.Futureになります。
private[concurrent] object Future {
class PromiseCompletingRunnable[T](body: => T) extends Runnable {
val promise = new Promise.DefaultPromise[T]()
override def run() = {
promise complete {
try Success(body) catch { case NonFatal(e) => Failure(e) }
}
}
}
def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] = {
val runnable = new PromiseCompletingRunnable(body)
executor.execute(runnable)
runnable.promise.future
}
}
ご覧のとおり、プロデューサーブロックから得られる結果は、約束に注がれます。
後で編集:
実世界での使用について:ほとんどの場合、約束を直接扱うことはありません。非同期計算を実行するライブラリを使用する場合は、ライブラリのメソッドによって返されるフューチャーを操作するだけです。この場合、Promiseはライブラリによって作成されます。これらのメソッドの機能の読み取り側で作業しているだけです。
ただし、独自の非同期APIを実装する必要がある場合は、それらのAPIの使用を開始する必要があります。Nettyの上に非同期HTTPクライアントを実装する必要があるとします。その後、コードは次のようになります
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}