Clojure future 和 Promise 有何不同?

发布于 2024-10-10 18:55:58 字数 52 浏览 6 评论 0原文

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

Both futures and promises block until they have calculated their values, so what is the difference between them?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

梦言归人 2024-10-17 18:55:58

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

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

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

请注意,在承诺中您明确交付您在以后的计算中选择的值(在本例中为 :fred)。另一方面,未来正在它被创造的地方被消耗。 some-expr 可能是在幕后启动并串联计算(最终),但如果在访问它时仍未对其进行计算,则线程会阻塞,直到它可用为止。


编辑添加

为了帮助进一步区分 Promise 和 Future,请注意以下内容:

promise

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

未来

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

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

Answering in Clojure terms, here are some examples from Sean Devlin's screencast:

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

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

Note that in the promise you are explicitly delivering a value that you select in a later computation (:fred in this case). The future, on the other hand, is being consumed in the same place that it was created. The some-expr is presumably launched behind the scenes and calculated in tandem (eventually), but if it remains unevaluated by the time it is accessed the thread blocks until it is available.


edited to add

To help further distinguish between a promise and a future, note the following:

promise

  1. You create a promise. That promise object can now be passed to any thread.
  2. You continue with calculations. These can be very complicated calculations involving side-effects, downloading data, user input, database access, other promises -- whatever you like. The code will look very much like your mainline code in any program.
  3. When you're finished, you can deliver the results to that promise object.
  4. Any item that tries to deref your promise before you're finished with your calculation will block until you're done. Once you're done and you've delivered the promise, the promise won't block any longer.

future

  1. You create your future. Part of your future is an expression for calculation.
  2. The future may or may not execute concurrently. It could be assigned a thread, possibly from a pool. It could just wait and do nothing. From your perspective you cannot tell.
  3. At some point you (or another thread) derefs the future. If the calculation has already completed, you get the results of it. If it has not already completed, you block until it has. (Presumably if it hasn't started yet, derefing it means that it starts to execute, but this, too, is not guaranteed.)

While you could make the expression in the future as complicated as the code that follows the creation of a promise, it's doubtful that's desirable. This means that futures are really more suited to quick, background-able calculations while promises are really more suited to large, complicated execution paths. Too, promises seem, in terms of calculations available, a little more flexible and oriented toward the promise creator doing the work and another thread reaping the harvest. Futures are more oriented toward automatically starting a thread (without the ugly and error-prone overhead) and going on with other things until you -- the originating thread -- need the results.

披肩女神 2024-10-17 18:55:58

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

对于Future计算是在Future创建时定义的,并且异步执行“尽快”开始。它还“知道”如何生成异步计算。

Promise的情况下,计算、其开始时间和[可能的]异步调用与交付机制解耦。当计算结果可用时,Producer必须显式调用deliver,这也意味着Producer控制何时结果可用。

对于Promise,Clojure 犯了一个设计错误,它使用同一个对象(promise 调用的结果)来生产(deliver)和消费(>deref计算的结果。这是两种截然不同的能力,应该如此对待。

Both Future and Promise are mechanisms to communicate result of asynchronous computation from Producer to Consumer(s).

In case of Future the computation is defined at the time of Future creation and async execution begins "ASAP". It also "knows" how to spawn an asynchronous computation.

In case of Promise the computation, its start time and [possible] asynchronous invocation are decoupled from the delivery mechanism. When computation result is available Producer must call deliver explicitly, which also means that Producer controls when result becomes available.

For Promises Clojure makes a design mistake by using the same object (result of promise call) to both produce (deliver) and consume (deref) the result of computation. These are two very distinct capabilities and should be treated as such.

向日葵 2024-10-17 18:55:58

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

两者

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

未来

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

Promise

创建 Promise 时不给出任何参数。该引用应该传递给其他将交付结果的“用户”线程。

There are already excellent answers so only adding the "how to use" summary:

Both

Creating promise or future returns a reference immediately. This reference blocks on @/deref until result of computation is provided by other thread.

Future

When creating future you provide a synchronous job to be done. It's executed in a thread from the dedicated unbounded pool.

Promise

You give no arguments when creating promise. The reference should be passed to other 'user' thread that will deliver the result.

少女净妖师 2024-10-17 18:55:58

在 Clojure 中,promisefuturedelay 是类似 Promise 的对象。它们都代表客户端可以使用 deref (或 @)等待的计算。客户端重用结果,这样计算就不会运行多次。

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

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

  • 当第一个客户端使用 derefforce 时,

    delay 将延迟执行计算。

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

In Clojure, promise, future, and delay are promise-like objects. They all represent a computation that clients can await by using deref (or @). Clients reuse the result, so that the computation is not run several times.

They differ in the way the computation is performed:

  • future will start the computation in a different worker thread. deref will block until the result is ready.

  • delay will perform the computation lazily, when the first client uses deref, or force.

  • promise offers most flexibility, as its result is delivered in any custom way by using deliver. You use it when neither future or delay match your use case.

谷夏 2024-10-17 18:55:58

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

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

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

然而,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 与任务定义和执行分离,现在可以用作线程之间的传输单元。

I think chapter 9 of Clojure for the Brave has the best explanation of the difference between delay, future, and promise.

The idea which unifies these three concepts is this: task lifecycle. A task can be thought of as going through three stages: a task is defined, a task is executed, a task's result is used.

Some programming languages (like JavaScript) have similarly named constructs (like JS's Promise) which couple together several (or all) of the stages in the task lifecycle. In JS, for instance, it is impossible to construct a Promise object without providing it either with the function (task) which will compute its value, or resolveing it immediately with a constant value.

Clojure, however, eschews such coupling, and for this reason it has three separate constructs, each corresponding to a single stage in the task lifecycle.

  1. delay: task definition
  2. future: task execution
  3. promise: task result

Each construct is concerned with its own stage of the task lifecycle and nothing else, thus disentangling higher order constructs like JS's Promise and separating them into their proper parts.

We see now that in JavaScript, a Promise is the combination of all three Clojure constructs listed above. Example:

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

Let's break it down:

  1. task definition: resolve(6) is the task.
  2. task execution: there is an implied execution context here, namely that this task will be run on a future cycle of the event loop. You don't get a say in this; you can't, for instance, require that this task be resolved synchronously, because asynchronicity is baked into Promise itself. Notice how in constructing a Promise you've already scheduled your task to run (at some unspecified time). You can't say "let me pass this around to a different component of my system and let it decide when it wants to run this task".
  3. task result: the result of the task is baked into the Promise object and can be obtained by thening or awaiting. There's no way to create an "empty" promised result to be filled out later by some yet unknown part of your system; you have to both define the task and simultaneously schedule it for execution.

PS: The separation which Clojure imposes allows these constructs to assume roles for which they would have been unsuited had they been tightly coupled. For instance, a Clojure promise, having been separated from task definition and execution, can now be used as a unit of transfer between threads.

我是有多爱你 2024-10-17 18:55:58

首先,Promise 是一个Future。我想你想知道 PromiseFutureTask 之间的区别。

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

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

Promise 代表承诺者将来向承诺者交付的结果。在这种情况下,您是承诺者,承诺者是向您提供 Promise 对象的人。与 FutureTask 类似,如果您尝试在履行 Promise 之前访问结果,它将被阻止,直到承诺者履行 Promise 为止。一旦履行了Promise,您就会立即获得相同的价值。与 FutureTask 不同,这里涉及另一方,即做出 Promise 的一方。另一方负责进行计算并履行Promise

从这个意义上说,FutureTask 是您对自己做出的Promise

Firstly, a Promise is a Future. I think you want to know the difference between a Promise and a FutureTask.

A Future represents a value that is not currently known but will be known in the future.

A FutureTask represents the result of a computation that will happen in future (maybe in some thread pool). When you try to access the result, if the computation has not happened yet, it blocks. Otherwise the result is returned immediately. There is no other party involved in the computing the result as the computation is specified by you in advance.

A Promise represents a result that will be delivered by the promiser to the promisee in future. In this case you are the promisee and the promiser is that one who gave you the Promise object. Similar to the FutureTask, if you try to access the result before the Promise has been fulfilled, it gets blocked till the promiser fulfills the Promise. Once the Promise is fulfilled, you get the same value always and immediately. Unlike a FutureTask, there is an another party involved here, one which made the Promise. That another party is responsible for doing the computation and fulfilling the Promise.

In that sense, a FutureTask is a Promise you made to yourself.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文