簡體   English   中英

scala.concurrent.Promise有什么用例?

[英]What are the use cases of scala.concurrent.Promise?

我正在閱讀SIP-14 ,而Future的概念非常有意義且易於理解。 但是有兩個關於Promise問題:

  1. SIP表示Depending on the implementation, it may be the case that p.future == p 怎么會這樣? FuturePromise不是兩種不同的類型嗎?

  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成為必要?

承諾與未來是互補的概念。 未來是一個價值,將在未來的某個時間檢索,並且當事件發生時你可以用它來做。 因此,它是計算的讀取或輸出端點 - 它是從中檢索值的東西。

類比而言,承諾是計算的寫作方面。 您創建一個承諾,即您將放置計算結果的地方,並從該承諾中獲得將用於讀取已放入承諾的結果的未來。 當您通過失敗或成功完成Promise時,您將觸發附加到關聯Future的所有行為。

關於你的第一個問題,對於一個承諾p怎么可能p.future == p 你可以想象這就像一個單項緩沖區 - 一個最初為空的容器,你可以在后面存儲一個永遠成為其內容的值。 現在,根據你的觀點,這既是承諾,也是未來。 對於打算在緩沖區中寫入值的人來說,這是有希望的。 對於等待將該值放入緩沖區的人來說,這是一個未來。

具體來說,對於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))

}

現在,可以在這里找到promises,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
  }
}

因此,正如您所看到的,您從生產者塊獲得的結果會被投入到承諾中。

后期編輯

關於現實世界的使用:大多數時候你不會直接處理承諾。 如果您將使用執行異步計算的庫,那么您將只使用庫的方法返回的期貨。 在這種情況下,承諾是由圖書館創建的 - 您只是在閱讀那些方法所做的閱讀結束。

但是,如果您需要實現自己的異步API,則必須開始使用它們。 假設您需要在Netty之上實現異步HTTP客戶端。 然后你的代碼看起來會像這樣

    def makeHTTPCall(request: Request): Future[Response] = {
        val p = Promise[Response]
        registerOnCompleteCallback(buffer => {
            val response = makeResponse(buffer)
            p success response
        })
        p.future
    }

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM