什么是scala.concurrent.Promise的用例?

我正在阅读SIP-14 , Future的概念非常有意义且易于理解。 但是有两个有关Promise问题:

  1. SIP说Depending on the implementation, it may be the case that p.future == p 。 怎么会这样? FuturePromise不是两种不同的types?

  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() } } 

这和给出的例子有什么区别,什么使得一个承诺是必要的?

“承诺与未来”是互补的概念。 未来是一个价值,它将在未来的某个时候被检索出来,当事件发生的时候,你可以用它做东西。 因此,它是计算的读出或终止端点 – 它是从中检索值的东西。

计算中的承诺是类比写作的一面。 你创造了一个承诺,就是你将把计算结果放在哪里,从这个承诺中你将得到一个将被用来读取被承诺的结果的未来。 当你完成一个承诺时,无论是失败还是成功,你都会触发连接到相关未来的所有行为。

关于你的第一个问题,对于一个承诺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)) } 

现在,可以在这里findPromise的实现,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是一个缓冲区,其值是从它的创build开始的。

关于你的例子,你在那里使用的未来模块实际上在背后创造了一个承诺。 下面我们来看看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 } } 

所以,正如你所看到的那样,你从生产者区块得到的结果将会涌入一个承诺。

后期编辑

关于现实世界的使用:大部分时间你不会直接处理承诺。 如果你使用一个执行asynchronous计算的库,那么你只需要处理库方法返回的期货。 在这种情况下,承诺是由图书馆创build的 – 你只是在阅读这些方法所做的工作。

但是如果你需要实现你自己的asynchronousAPI,你将不得不开始使用它们。 假设你需要在Netty之上实现一个asynchronous的HTTP客户端。 那么你的代码看起来就像这样

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