澄清需要关于Scala的期货和承诺

我试图让我的头在斯卡拉的承诺和未来的build设。

我一直在阅读Scala文档中的期货和承诺 ,并且有些困惑,因为我有一种感觉,承诺和期货的概念混在一起。

在我的理解中,一个承诺是一个容器,我们可以在以后的时间内填充价值。 而未来是某种asynchronous操作,可以在不同的执行path中完成。

在Scala中,我们可以使用附加的callback来获得结果。

我失去的是承诺有未来吗?

我也曾经在Clojure上看过这些概念,假设承诺和未来有一些通用的概念,但似乎我错了。

诺言p完成未来回报的未来。 这个未来是对承诺的具体体现。 根据实施情况,情况可能是p.future eq p。

val p = promise[T] val f = p.future 

你可以将期货和承诺视为pipe道的两个不同方面。 在承诺方面,数据被推入,而未来的方面,数据可以被抽出。

而未来是某种asynchronous操作,可以在不同的执行path中完成。

实际上,未来是一个占位符对象 ,可以在某个时间点asynchronous地获得某个值。 这不是asynchronous计算本身。

事实上,有一个名为future的未来构造函数返回这样一个占位符对象, 产生一个完成此占位符对象的asynchronous计算并不意味着asynchronous计算被称为未来 。 还有其他未来的build设者/工厂方法 。

但是,我不明白的是,诺言有未来吗?

将承诺和期货划分为两个独立的界面是一个devise决策。 你可以在同一个接口Future下使用这两个接口,但是这样可以让期货客户完成它们,而不是完成未来的预期完成。 这会导致意想不到的错误,因为可能有任何数量的争用完成者。

例如,对于future构造产生的asynchronous计算,将不再清楚是否必须完成承诺,或者如果客户将这样做。

期货和承诺的目的是限制数据在程序中的stream动。 这个想法是有一个未来的客户订阅的数据,一旦数据到达就作用于它。 承诺客户的angular色是提供这些数据。 混合这两个angular色可能导致程序难以理解或推理。

你也许会问为什么Promise特性不能延伸Future 。 这是阻止程序员盲目地将Promise传递给客户的另一个devise决策,他们应该把Promise to Future (这个Upcast很容易被遗漏,而不得不明确地调用future的承诺保证你每次调用它)。 换句话说,通过回复承诺,您有权将其完成给其他人,并通过返回未来,您有权订阅。

编辑:

如果您想了解更多有关未来的信息,请参阅“Scala学习并行编程”一书中的第4章。 免责声明:我是这本书的作者。

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

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

在scala和clojure中, 期货 (除非由其他函数/方法返回)用一些计算创build:

 // scala future { do_something() } ;; clojure (future (do-something)) 

在这两种情况下,未来的“回报价值”只有在计算结束后才能被读取(没有阻塞)。 当这种情况通常在程序员的控制之外,因为计算在后台的某个线程(池)中执行。

相反,在这两种情况下, 承诺都是最初是空的容器,稍后可以填充(恰好一次):

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

一旦发生这种情况可以阅读。

读取期货和承诺是通过clojure(通过deref完成的(并且可以用来检查deref是否会被阻止)。 在scala阅读是通过Future特质提供的方法完成的。 为了读取承诺的结果,我们必须得到一个实现Future的对象,这是由p.future完成的。 现在如果Future是由Promise实现的,那么p.future可以返回this ,并且两者是平等的。 这纯粹是实现的select,不会改变概念。 所以你没有错! 在任何情况下,期货主要是使用callback处理。

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

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

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

请注意,引擎盖下Future是按照Promise来实现的,这个Promise是通过你传递给你Future的身体来完成的:

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

impl.Future是Future特性的一个实现:

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

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

所以你看,即使他们是独立的概念,你可以在现实中独立使用,但如果没有使用Promise你将无法获得Future