Both futures and promises block until they have calculated th开发者_如何转开发eir values, so what is the difference between them?
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
- You create a
promise
. That promise object can now be passed to any thread. - 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.
- When you're finished, you can
deliver
the results to that promise object. - 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'vedeliver
ed the promise, the promise won't block any longer.
future
- You create your future. Part of your future is an expression for calculation.
- 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.
- At some point you (or another thread)
deref
s 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,deref
ing 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.
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.
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.
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 usesderef
, orforce
.promise
offers most flexibility, as its result is delivered in any custom way by usingdeliver
. You use it when neitherfuture
ordelay
match your use case.
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 resolve
ing 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.
delay:
task definitionfuture
: task executionpromise
: 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:
- task definition:
resolve(6)
is the task. - 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 aPromise
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". - task result: the result of the task is baked into the
Promise
object and can be obtained bythen
ing orawait
ing. 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.
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.
精彩评论