97

私はSIP-14を読んでいますが、その概念Futureは完全に理にかなっていて理解しやすいものです。しかし、以下について 2 つの質問がありPromiseます。

  1. SIP は言うDepending on the implementation, it may be the case that p.future == p。どうすればいいの?FuturePromiseではなく、2 つの異なるタイプですか?

  2. いつ使用する必要がありPromiseますか?サンプルproducer and consumerコード:

    import scala.concurrent.{ future, promise }
    val p = promise[T]
    val f = p.future
    
    val producer = future {
        val r = produceSomething()
        p success r
        continueDoingSomethingUnrelated()
    }
    val consumer = future {
        startDoingSomething()
        f onSuccess {
            case r => doSomethingWithResult()
        }
    }
    

は読みやすいですが、本当にそのように書く必要がありますか? 次のように、Future のみで Promise なしで実装しようとしました。

val f = future {
   produceSomething()
}

val producer = future {
   continueDoingSomethingUnrelated()
}

startDoingSomething()

val consumer = future {
  f onSuccess {
    case r => doSomethingWithResult()
  }
}

これと与えられた例の違いは何ですか?また、何が Promise を必要とするのですか?

4

1 に答える 1

123

約束と未来は補完的な概念です。Future は、将来のいつか取得される値であり、そのイベントが発生したときに何かを行うことができます。したがって、これは計算の読み取りまたは出力エンドポイントであり、値を取得するものです。

Promise は、類推すると、計算の書き込み側です。計算の結果を入れる場所であるプロミスを作成し、そのプロミスから、プロミスに入れられた結果を読み取るために使用される未来を取得します。失敗または成功によって Promise を完了すると、関連する 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でinの定義を見てみましょう:

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 に注がれます。

後で編集

実際の使用に関して: ほとんどの場合、Promise を直接扱うことはありません。非同期計算を実行するライブラリを使用する場合は、ライブラリのメソッドによって返される先物を操作するだけです。この場合、プロミスはライブラリによって作成されます。これらのメソッドが行うことの読み取り側で作業しているだけです。

ただし、独自の非同期 API を実装する必要がある場合は、それらを使用して作業を開始する必要があります。たとえば、Netty の上に非同期 HTTP クライアントを実装する必要があるとします。次に、コードは次のようになります

    def makeHTTPCall(request: Request): Future[Response] = {
        val p = Promise[Response]
        registerOnCompleteCallback(buffer => {
            val response = makeResponse(buffer)
            p success response
        })
        p.future
    }
于 2012-11-14T22:39:15.623 に答える