![](/img/trans.png)
[英]Error replacing play.api.libs.concurrent.Promise with scala.concurrent.Promise
[英]What are the use cases of scala.concurrent.Promise?
我正在閱讀SIP-14 ,而Future
的概念非常有意義且易於理解。 但是有兩個關於Promise
問題:
SIP表示Depending on the implementation, it may be the case that p.future == p
。 怎么會這樣? Future
和Promise
不是兩種不同的類型嗎?
我們什么時候應該使用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.