什么是scala.concurrent.Promise的用例?
我正在阅读SIP-14 , Future
的概念非常有意义且易于理解。 但是有两个有关Promise
问题:
-
SIP说
Depending on the implementation, it may be the case that p.future == p
。 怎么会这样?Future
和Promise
不是两种不同的types? -
我们什么时候应该使用
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 }