91

futures 和 promises 都会阻塞,直到它们计算出它们的值,那么它们之间有什么区别呢?

4

6 回答 6

56

用 Clojure 术语回答,以下是Sean Devlin 截屏视频中的一些示例:

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

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

请注意,在 Promise 中,您明确提供了您在以后的计算中选择的值(:fred在这种情况下)。另一方面,未来正在被创造的地方消费。大概是在some-expr幕后启动并串联计算(最终),但如果它在被访问时仍未评估,则线程阻塞直到它可用。


编辑添加

为了帮助进一步区分承诺和未来,请注意以下几点:

承诺

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

未来

  1. 你创造你的未来。你未来的一部分是计算的表达。
  2. 未来可能会或可能不会同时执行。它可以被分配一个线程,可能来自一个池。它只能等待,什么也不做。从您的角度来看,您无法分辨
  3. 在某些时候,你(或另一个线程)deref是未来。如果计算已经完成,你会得到它的结果。如果它还没有完成,你会阻塞直到它完成。(大概如果它还没有开始,derefing 意味着它开始执行,但这也不能保证。)

虽然您可以使将来的表达式像创建 promise 之后的代码一样复杂,但是否可取是值得怀疑的。这意味着future 真的更适合快速、后台计算,而promise 更适合大型、复杂的执行路径。同样,就可用计算而言,promise 似乎更灵活一些,并且面向做工作的 promise 创建者和另一个收获收获的线程。Futures 更倾向于自动启动一个线程(没有丑陋和容易出错的开销)并继续处理其他事情,直到您 - 发起线程 - 需要结果。

于 2011-01-07T09:12:37.193 回答
27

Future 和 Promise 都是将异步计算结果从生产者传递给消费者的机制。

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

Promise计算的情况下,它的开始时间和 [可能的]异步调用与传递机制分离。当计算结果可用时,Producer 必须deliver显式调用,这也意味着 Producer 控制结果何时可用。

对于Promises,Clojure 使用相同的对象(promise调用结果)来生成(deliver)和消耗(deref计算结果,这是一个设计错误。这是两个非常不同的功能,应该这样对待。

于 2012-07-31T18:19:40.623 回答
4

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

两个都

创建 promise 或 future 会立即返回一个引用。这个引用在 @/deref 上阻塞,直到其他线程提供计算结果。

未来

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

承诺

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

于 2013-04-10T11:01:04.993 回答
1

在 Clojure 中promisefuture、 和delay是类似 Promise 的对象。它们都表示客户端可以通过使用deref(或@)等待的计算。客户端重用结果,因此计算不会运行多次。

它们的不同之处在于执行计算的方式:

  • future将在不同的工作线程中开始计算。deref将阻塞直到结果准备好。

  • delay当第一个客户端使用deref, 或时,将懒惰地执行计算force

  • promise提供最大的灵活性,因为它的结果是通过使用deliver. 当两者都不匹配future或不delay匹配您的用例时,您会使用它。

于 2020-06-16T11:02:05.627 回答
0

我认为Clojure for the Brave的第 9 章对delay,futurepromise.

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

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

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

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

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

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

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

让我们分解一下:

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

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

于 2021-07-06T19:39:53.533 回答
-4

首先,aPromiseFuture。我想你想知道 aPromise和 a之间的区别FutureTask

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

AFutureTask表示将来会发生的计算结果(可能在某个线程池中)。当您尝试访问结果时,如果计算尚未发生,它会阻塞。否则立即返回结果。由于计算是您事先指定的,因此计算结果不涉及任何其他方。

APromise表示未来将由承诺人交付给被承诺人的结果。在这种情况下,您是被许诺者,而许诺者是给您Promise对象的人。与 类似FutureTask,如果您尝试在Promise完成之前访问结果,它将被阻止,直到承诺者完成Promise. 一旦Promise满足,您将始终立即获得相同的值。与 a 不同的是FutureTask,这里涉及到另一方,它使Promise. 另一方负责进行计算并完成Promise.

从这个意义上说,aFutureTaskPromise你为自己创造的。

于 2011-01-07T08:04:45.223 回答