Clojure期货与承诺有何不同?

时间:2011-01-07 07:51:18

标签: clojure terminology future promise

期货和承诺都会阻止,直到他们计算出它们的价值,那么它们之间有什么区别呢?

6 个答案:

答案 0 :(得分:50)

回答Clojure术语,这里有一些来自Sean Devlin's screencast的例子:

(def a-promise (promise))
(deliver a-promise :fred)

(def f (future (some-sexp)))
(deref f)

请注意,在承诺中,您明确提供了在稍后的计算中选择的值(在本例中为:fred)。另一方面,未来正在被创造的同一个地方消费。 some-expr可能是在幕后启动并串联计算(最终),但如果在访问它时它仍未被评估,则线程会阻塞直到它可用。


已编辑以添加

为了进一步区分承诺和未来,请注意以下事项:

  1. 您创建了promise。该promise对象现在可以传递给任何线程。
  2. 您继续进行计算。这些可能是非常复杂的计算,涉及副作用,下载数据,用户输入,数据库访问,其他承诺 - 无论您喜欢什么。代码看起来非常类似于任何程序中的主线代码。
  3. 完成后,您可以deliver将结果发送到该承诺对象。
  4. 在您完成计算之前尝试deref您的承诺的任何项目都会阻止,直到您完成为止。一旦你完成并且deliver承诺,承诺将不再阻止。
  5. 将来

    1. 你创造了自己的未来。你未来的一部分是计算的表达。
    2. 未来可能同时执行也可能不会同时执行。可以从池中为其分配一个线程。它可以等待,什么都不做。从您的角度来看你无法告诉
    3. 在某些时候你(或另一个线程)deref是未来。如果计算已经完成,您将获得结果。如果尚未完成,则阻止直至完成。 (大概如果还没有开始,deref意味着它开始执行,但这也不能保证。)
    4. 虽然你可以使表达在将来像创建一个承诺之后的代码一样复杂,但是这是值得怀疑的。这意味着期货更适合快速,可进行背景的计算,而承诺更适合于大型,复杂的执行路径。在可用的计算方面,承诺似乎更加灵活,并且面向承诺创造者完成工作,另一个线索收获丰收。期货更倾向于自动启动一个线程(没有丑陋和容易出错的开销)并继续其他事情,直到你 - 原始线程 - 需要结果。

答案 1 :(得分:23)

Future和Promise都是将生产者与消费者之间的异步计算结果进行通信的机制。

Future 的情况下,计算在创建Future时定义,异步执行开始“ASAP”。它还“知道”如何产生异步计算。

如果承诺 计算,其开始时间和[可能] 异步调用将与传递机制分离。当计算结果可用时,生产者必须明确调用deliver,这也意味着当结果可用时,生产者控制

对于 Promises Clojure通过使用相同的对象(promise调用的结果)来产生(deliver)和消耗(deref)结果,从而导致设计错误计算。这是两个截然不同的能力,应该这样对待。

答案 2 :(得分:2)

已经有很好的答案,所以只添加“如何使用”摘要:

<强>两个

创建承诺或将来立即返回引用。该引用在@ / deref上阻塞,直到其他线程提供计算结果。

<强>未来

创建未来时,您需要提供同步作业。它是在专用的无界池中的一个线程中执行的。

<强>无极

创建承诺时不提供任何参数。该引用应该传递给deliver结果的其他“用户”线程。

答案 3 :(得分:1)

在Clojure中,promisefuturedelay是类似诺言的对象。它们都表示客户端可以使用deref(或@)等待的计算。客户端重复使用结果,因此计算不会多次运行。

它们的计算方式不同:

  • future将在其他工作线程中启动计算。 deref将阻塞直到结果准备就绪。

  • delay将在第一个客户端使用derefforce时延迟执行计算。

  • promise提供了最大的灵活性,因为其结果可以通过使用deliver以任何自定义方式进行传递。当futuredelay都不符合用例时,就使用它。

答案 4 :(得分:0)

我认为 Clojure for the Brave 的第 9 章对 delayfuturepromise 之间的区别有最好的解释。

统一这三个概念的想法是:任务生命周期。一个任务可以被认为经历了三个阶段:一个任务被定义,一个任务被执行,一个任务的结果被使用。

某些编程语言(如 JavaScript)具有类似命名的构造(如 JS 的 Promise),它们将任务生命周期中的几个(或所有)阶段耦合在一起。例如,在 JS 中,如果不为其提供计算其值的函数(任务)或立即使用常量值Promise对其进行赋值,就不可能构造一个 resolve 对象。

然而,Clojure 避免了这种耦合,因此它具有三个独立的构造,每个构造对应于任务生命周期中的一个阶段。

  1. delay: 任务定义
  2. future:任务执行
  3. promise:任务结果

每个构造都只关心它自己的任务生命周期阶段,而不是其他任何东西,从而解开像 JS 的 Promise 这样的高阶构造并将它们分成适当的部分。

我们现在看到,在 JavaScript 中,Promise 是上面列出的所有三个 Clojure 结构的组合。示例:

const promise = new Promise((resolve) => resolve(6))

让我们分解一下:

  1. 任务定义:resolve(6) 是任务。
  2. 任务执行:这里有一个隐含的执行上下文,即该任务将在事件循环的未来循环中运行。你在这方面没有发言权;例如,您不能要求同步解决此任务,因为异步性已融入 Promise 本身。请注意在构建 Promise 时您如何已经安排您的任务运行(在某个未指定的时间)。你不能说“让我把它传递给我系统的另一个组件,让决定什么时候运行这个任务”。
  3. 任务结果:任务的结果被烘焙到Promise对象中,可以通过thening或awaiting获得。没有办法创建一个“空”的承诺结果,稍后由系统中某些未知的部分填写;您必须定义任务并同时安排它执行。

PS:Clojure 强加的分离允许这些构造承担如果它们紧密耦合它们将不适合的角色。例如,Clojure promise 已经与任务定义和执行分离,现在可以用作线程之间的传输单元。

答案 5 :(得分:-3)

首先,PromiseFuture。我想您想知道PromiseFutureTask之间的区别。

Future表示当前未知但将来会知道的值。

FutureTask表示将来会发生的计算结果(可能在某个线程池中)。当您尝试访问结果时,如果计算尚未发生,则会阻止。否则结果立即返回。由于计算是由您事先指定的,因此没有其他方参与计算结果。

Promise表示未来承诺人将向承诺人提供的结果。在这种情况下,您是受诺者,而承诺者就是那个给您Promise对象的人。与FutureTask类似,如果您在Promise完成之前尝试访问结果,则会被阻止,直到承销商履行Promise为止。完成Promise后,您会立即获得相同的值。与FutureTask不同,此处涉及另一方,其中一方是Promise。另一方负责进行计算并完成Promise

从这个意义上说,FutureTask是你自己制作的Promise