承诺和未来是互补的概念。Future 是一个值,可以在未来的某个时间被检索到,当事件发生时你可以用它做一些事情。因此,它是计算的读取或输出端点——它是您从中检索值的东西。
以此类推,Promise 是计算的写入端。您创建了一个 Promise,您将在其中放置计算结果,并从该 Promise 中获得一个未来,该未来将用于读取放入 Promise 的结果。当你通过失败或成功完成一个 Promise 时,你将触发所有附加到相关 Future 的行为。
关于您的第一个问题,对于我们的承诺 p 怎么可能p.future == p
。你可以把它想象成一个单项缓冲区——一个最初是空的容器,你可以在后面存储一个值,该值将永远成为它的内容。现在,根据您的观点,这既是承诺也是未来。对于打算将值写入缓冲区的人来说,这是一个承诺。对于等待将该值放入缓冲区的人来说,这是一个未来。
具体来说,对于 Scala 并发 API,如果您在这里查看 Promise trait,您可以看到 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))
}
现在,可以在这里找到那些承诺的实现,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,则必须开始使用它们。假设您需要在 Netty 之上实现一个异步 HTTP 客户端。然后你的代码看起来有点像这样
def makeHTTPCall(request: Request): Future[Response] = {
val p = Promise[Response]
registerOnCompleteCallback(buffer => {
val response = makeResponse(buffer)
p success response
})
p.future
}