Clojure的期货和承诺有何不同?


86

期货和承诺都将阻塞,直到它们计算出它们的值为止,那么它们之间有什么区别?


8
我不确定为什么在问题上为-1,还是在问坏问题之前不知道答案的问题?
只是我的正确观点,

我没有-1的答案??我们如何知道谁在问题或答案上加上-1?
appshare.co

你和我不能,祖拜尔。我只是很好奇谁会在您的问题上加上-1,因为这是一个完全合理的问题,因此对于SO来说绝对是话题。
我的正确观点

Answers:


54

用Clojure的术语回答,这里有一些Sean Devlin的截屏示例:

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

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

请注意,在Promise中,您将明确提供在以后的计算中选择的值(:fred在这种情况下)。另一方面,在创建的地方消耗了未来。在some-expr据推测幕后推出,串联(最终)计算的,但如果它仍然通过的时间不计算被访问线程块,直到它可用。


编辑添加

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

诺言

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

未来

  1. 您创造未来。未来的一部分是计算的表达式。
  2. 将来可能会并发执行,也可能不会并发执行。可以从一个池中为其分配一个线程。它可能只是等待而什么也不做。从你的角度看你无法分辨
  3. 在某个时候,您(或另一个线程)deref是未来。如果计算已经完成,您将得到结果。如果尚未完成,请阻塞直到完成。(假设它尚未启动,deref则表示它开始执行,但这也不能保证。)

尽管将来您可以使表达式的表达与创建promise的代码一样复杂,但令人怀疑的是,是否可取。这意味着期货确实更适合于快速的,可在后台进行的计算,而承诺确实更适合于大型,复杂的执行路径。根据可用的计算,promise似乎也更加灵活一些,并且面向promise创建者进行工作和另一个收获丰收的线程。期货的方向是自动启动线程(没有丑陋且容易出错的开销),并继续进行其他操作,直到您(始发线程)需要结果为止。


但是您可以有任何计算障碍,直到许诺或未来完成。即:(@a + @b)在未来和承诺中都将发挥作用
appshare.co

2
答应给我带来更大的灵活性。我创造一个诺言。我将那个承诺传递给另一个线程。然后,我可以进行许多复杂的计算,包括等待I / O,从Internet下载数据,等待用户输入等。完成所有操作后,我将兑现承诺并带来最终的价值。未来涵盖一个S表达式。我猜想它可能是非常非常复杂的S表达式,但是在那儿有点僵硬。此外,future会在线程(或池)中自动工作。在诺言中做到同样意味着更多的工作。
只是我的正确意见,

FWIW,因为单个s表达式可以是对任意代码路径的调用,所以不一定要填充多少代码到表达式中。因此,与其说承诺是“更灵活的”,不如说它的目的是完全不同的。否则,为什么两者都有?
杰夫2012年

2
仅作记录,future呼叫的主体可以包括N个sexprs。
vemv

此解释应该是Clojure Doc
Piyush Katariya的

25

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

如果是Future,则在创建Future时定义计算,并且异步执行从“ ASAP”开始。它还“知道”如何产生异步计算。

如果有诺言计算,它的开始时间和[可能]异步调用从输送机构分离。当计算结果可用时,生产者必须deliver显式调用,这也意味着生产者控制结果何时可用。

对于承诺, Clojure通过使用同一对象(promise调用结果)同时产生(deliver)和消耗(deref计算结果而犯了设计错误。这是两个非常不同的功能,因此应将其视为。


@oskarkv假设您已经创建了一个诺言并将其提供给3个客户。没有什么可以阻止其中一个客户端以假结果来解决它并将其发信号给其他两个客户端的。另外,您将无法再履行这一诺言。相反,如果您有一个Promise +解析器对,给您的客户一个承诺,并自己保留解析器,那么这种情况就不可能了。有关更多信息,建议的搜索词是“基于功能的访问控制”和“基于功能的安全性”。
Dimagog

1
我不确定是否将安全性与这样的简单引用类型(请检查其隐含形式)结合起来promise是否方便。“邪恶”的消费者很少见;没有什么可以阻止您在promise之上构建自己的抽象。
vemv

8
这与安全性无关,而恰恰是经常基于安全性描述基于功能的编程。在这里,所有内容都与代码正确性有关。经常使用的术语是“通过构造正确”,而问题是“您可以构造不正确的程序”吗?不是故意的,而是偶然的。使用单个Promise对象可以,而不能使用两个单独的对象。
Dimagog

没有什么可以阻止您返回无法兑现的承诺的,如果您要的是: (defn undeliverable-promise [] (let [p (promise)] (reify clojure.lang.IDeref (deref [_] (deref p)) clojure.lang.IBlockingDeref (deref [_ ms val] (deref p ms val)) clojure.lang.IPending (isRealized [_] (.isRealized p)) clojure.lang.IFn (invoke [_ _] nil))))
tapichu 2014年

指出计算机制如何分离的差异使这篇文章变得非常简洁。谢谢!
synthomat

3

已经有了出色的答案,因此仅添加“使用方法”摘要:

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

未来

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

诺言

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


1

在Clojure中,promisefuture,和delay是承诺状物体。它们都代表客户端可以通过使用deref(或@)。客户端重复使用结果,因此计算不会多次运行。

它们的执行方式不同:

  • future将在其他工作线程中开始计算。deref将阻塞,直到结果准备好为止。

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

  • promise提供了最大的灵活性,因为使用可以以任何自定义的方式传递结果deliver。您可以使用它时,既不futuredelay符合您的使用案例。


-4

首先,aPromise是a Future。我认为您想知道aPromise和a之间的区别FutureTask

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

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

APromise表示承诺者将来会交付给承诺者的结果。在这种情况下,您是应许者,而应许者是向您提供Promise对象的那个人。与相似FutureTask,如果您尝试在Promise未完成之前访问结果,则结果将被阻塞,直到承诺者完成为止Promise。一旦Promise实现,您将始终且立即获得相同的值。与a不同FutureTask,这里有另一方参与,由另一方参与Promise。由另一方负责计算和完成交易Promise

从这个意义上讲,aFutureTaskPromise您为自己创造的。


您确定承诺是未来吗?我找不到它实现的接口。github.com/richhickey/clojure/blob/…–
Mikael Sundberg

对不起,我输入错误。我的问题已更改
Mikael Sundberg

我的回答是一般意义上的,而不是Clojure特定的答案。
Abhinav Sarkar

9
用Java代码回答有关Clojure的问题似乎有些古怪。
正确的意见
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.