需要澄清斯卡拉的未来和承诺

nis*_*013 42 scala

我试图了解Scala的承诺和未来的结构.

我一直在阅读Scala文档中的期货和承诺,我感到有点困惑,因为我觉得承诺和期货的概念是混淆的.

在我的理解中,承诺是一个容器,我们可以在以后填充价值.未来是某种异步操作,可以在不同的执行路径中完成.

在Scala中,我们可以使用附加的回调来获得结果.

我迷失的地方是未来的承诺?

我也在Clojure中读过这些概念,假设承诺和未来有一些通用的共同概念,但似乎我错了.

承诺p完成了p.future返回的未来.这个未来特定于承诺p.根据实施情况,可能是p.future eq p.

val p = promise[T]
val f = p.future
Run Code Online (Sandbox Code Playgroud)

axe*_*l22 72

您可以将期货和承诺视为管道的两个不同方面.在承诺方面,数据被推入,并且在未来方面,数据可以被拉出.

未来是某种异步操作,可以在不同的执行路径中完成.

实际上,future是一个占位符对象,它可以在某个时间点异步地变为可用的值.它不是异步计算本身.

事实上,有一个未来的构造函数被调用future,返回这样一个占位符对象,产生一个完成这个占位符对象的异步计算并不意味着异步计算被称为未来.还有其他未来的构造函数/工厂方法.

但我没有得到的是承诺未来的前景如何?

将承诺和期货分成两个独立的界面是一个设计决策.你可以在同一个界面下拥有这两个Future,但这将允许期货的客户完成它们而不是未来的预期完成者.这会导致意外错误,因为可能存在任意数量的竞争完成者.

例如,对于由future构造产生的异步计算,它将不再清楚是否必须完成承诺,或者客户端是否必须这样做.

期货和承诺旨在限制程序中的数据流.我们的想法是让未来的客户端在数据到达后订阅数据以对其进行操作.promise客户端的作用是提供该数据.混合这两种角色可能会导致程序难以理解或推理.

您可能还会问为什么Promise特征不会扩展Future.这是另一个设计决定从盲目传球劝阻程序员Promises到客户,他们应该上溯造型的PromiseFuture(这上溯造型很容易被排除在外,而具有显式调用future上的承诺,确保你调用每次它).换句话说,通过退回承诺,您有权将其完成给其他人,并通过返回未来,您有权订阅它.

编辑:

如果您想了解有关未来的更多信息,Scala中的学习并发编程手册中的第4章将详细介绍它们.免责声明:我是这本书的作者.

  • 喜欢最后一句话,"通过返回一个承诺,你有权将其完成给其他人,并通过返回未来,你有权订阅它",我认为它对创造未来/承诺. (8认同)
  • 这个评论应该在http://docs.scala-lang.org/overviews/core/futures.html上 (4认同)
  • 这是对的 - 您可以在单线程上下文中使用promise和future,例如,您可以在对future/promise对象具有不同访问权限的各种协程之间进行切换. (3认同)
  • 是 - promise是一个可以放置值(或错误)的对象.一旦承诺完成,将完成与特定承诺相对应的未来.甚至用于异步计算的`future`结构也有一个隐藏的承诺 - 但客户从来没有看到它阻止他完成它. (2认同)

sub*_*sub 15

两者之间的区别在于,期货通常以计算为中心,而承诺以数据为中心.

看来你的理解与此相符,但让我解释一下我的意思:

在这两个阶和Clojure的期货是(除非通过某些其它功能/方法返回)创建了一些计算:

// scala
future { do_something() }

;; clojure
(future (do-something))
Run Code Online (Sandbox Code Playgroud)

在这两种情况下,只有在计算终止后才能读取(不阻塞)未来的"返回值".在这种情况下,通常在程序员的控制之外,因为计算在后台的某个线程(池)中执行.

相比之下,在两种情况下,promises都是一个最初为空的容器,以后可以填充(只需一次):

// scala
val p = promise[Int]
...
p success 10 // or failure Exception()

;; clojure
(def p (promise))
(deliver p 10) 
Run Code Online (Sandbox Code Playgroud)

一旦出现这种情况,就可以阅读.

阅读期货和承诺是通过derefclojure 完成的(realized?可以用来检查是否deref会阻止).在scala中,通过Future特征提供的方法完成阅读.为了读取一个promise的结果,我们必须获得一个实现Future的对象,这是通过p.future.现在如果特征Future是由a实现的Promise,则p.future可以返回this并且两者相等.这纯粹是一种实现选择,不会改变概念.所以你没错! 在任何情况下,期货主要使用回调来处理.

在这一点上,重新考虑这两个概念的初步表征可能是值得的:

期货表示将在某一点产生结果的计算.让我们看一个可能的实现:我们在某个线程(池)中运行代码,一旦完成,我们就安排使用返回值来实现一个promise.因此,阅读未来的结果就是阅读一个承诺; 这是clojure的思维方式(不一定是实现方式).

另一方面,承诺代表将在某个时刻填补的价值.当它被填满时,这意味着某些计算产生了结果.所以在某种程度上这就像是未来的完成,所以我们应该使用回调以相同的方式消耗价值; 这是斯卡拉的思维方式.


gor*_*ral 5

请注意,内幕Future是根据来实现的,PromisePromise通过传递给您的主体来完成Future

def apply[T](body: =>T): Future[T] = impl.Future(body)  //here I have omitted the implicit ExecutorContext
Run Code Online (Sandbox Code Playgroud)

impl.Future是Futuretrait的一种实现:

def apply[T](body: =>T)(implicit executor: ExecutionContext): scala.concurrent.Future[T] =
{
  val runnable = new PromiseCompletingRunnable(body)
  executor.prepare.execute(runnable)
  runnable.promise.future
}
Run Code Online (Sandbox Code Playgroud)

PromiseCompletingRunnable这个样子的:

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) }
  }
} }
Run Code Online (Sandbox Code Playgroud)

因此,即使它们是独立的概念,您也可以看到它们在现实中可以独立使用,Future而不必使用它们Promise