A few weeks ago I posted about my initial impressions of CommonJS’s approach to concurrency, in particular the use of promises. Today I add my look at promises and futures in Clojure.
I’m aware that I’m kind of writing these blog posts backwards. I’m learning more as I go, which means before I’m done I will no doubt regret things I have written in these opening posts. Oh well.
In Clojure, as in CommonJS, a promise is also a stand-in for an asynchronously-computed value. As Rich Hickey explains in his change notes for the 1.1 release:
A promise is a synchronization construct that can be used to deliver a value from one thread to another. Until the value has been delivered, any attempt to dereference the promise will block.
A future, however, represents a unit of computation that can be executed on another thread.
Futures represent asynchronous computations. They are a way to get code to run in another thread, and obtain the result.
(def a-promise (promise))
(deliver a-promise :fred)
(def f (future (some-sexp)))
(deref f) ; blocks the thread that derefs f until value is available
There’s a lot of commentary out there, especially on this thread from the Clojure Google group in which different use cases for the abstractions are offered. Here are some highlights:
Laurent Petit offers this explanation of the virtues of futures and promises:
It’s an easy way to make a computation done in thread A (and using a pre-declared promise) block until thread B has delivered the promise (given it its value).
Sean Devlin adds that they are useful in dealing with mechanical objects. Instead of a while-loop to wait for an external condition to be satisfied, you can block on the value of a promise while a separate process devoted to detecting this desired condition delivers a value to the promise when and if the desired condition is met.
Finally, the venerable Chouser offers another example of blocking: setting a promise and then making an RPC call that delivers its result to the promise when it is complete.
Some general background: Dataflow concurrency
Rich Hickey, in his Clojure 1.1 release notes, and Laurent Petit, on the Clojure mailing list, point out that promises and futures support dataflow programming. Dataflow programming is laid out in some detail in a 900-page textbook. There are also less complete explanations of it online.
The wikipedia entry for dataflow concurrency is predictably terse and dense.
A dataflow network is a network of concurrently executing processes or automata that can communicate by sending data over channels (see message passing.)
I found the description of dataflow concurrency in Groovy by the folks at Codehaus very illuminating. Basically, they define three tasks, each of which determines a value for one of three DataFlowVariables x, y, and z.
These run in parallel, and, it’s implied, the first task is blocked until a value for z is available. Once that’s accomplished, the println line executes.
In Clojure, then, would x, y, and z be promises, and the tasks be closures sent to agents?
So this is a nice way to parallelize computation. One thread can hold the final piece of the computation and wait for others to deliver values to the promise(s) it needs. These other threads can similarly wait on other ones. This seems to replace the use of
await for agents, at least in some cases.
Strangely, I get this example better than the ones that just sleep threads and print “here I am” messages. Have I become math-biased? If so, I blame SICP.
Next up: promises and futures in wordy languages