Skip to content

A look at Clojure Concurrency primitives: delay, future and promise

August 14, 2012

As I was reading through the excellent book, Clojure Programming book by Chas Emerick, Brian Carper and Christophe Grand, I got to the part on Concurrency and felt that I should write about these primitives as a taste of what concurrency is like in Clojure. I highly recommend reading the book as it explains these concepts far better than I could in this short post!

So, quick rundown of these handy constructs:

Delay

delay wraps up an arbitrary body of code for evaluation at a later stage (when it is required) so that the code in question isn’t run unless asked. This will also cache the result value of the code to prevent another execution. This means that the code is guaranteed to only run once, even if dereferenced concurrently. A small REPL example (the “user>” bit being the REPL prompt) :

user> (def d (delay (println "Hello world!") 42))
#'user/d
user> d
#<Delay@320dafa2: :pending>
user> (realized? d)
false
user> @d
Hello world!
42
user> @d
42
user> (realized? d)
true
user> d
#<Delay@320dafa2: 42>

Here first assign the delay to a var, arbitrarily called ‘d’, if we look at it, we can see it starts in a pending state. We can then check if it has been run with the realized? function – dereferencing it (with the @) causes the code to run and Hello world! printed. Notice that the second @d does not print Hello world! again.

Future

This is a simple way of spinning off a new thread to do some computation or I/O that you will need access to in the (surprise!) future. The call is entirely compatible with delay, so you can swap them out if you want to start the work immediately. If you dereference a future, it will block until the value is available – REPL example :

user> (def do-something (future (Thread/sleep 10000) 28))
#'user/do-something
user> do-something
#<core$future_call$reify__6110@14c55ea: :pending>
user> (realized? do-something)
false

… 10 seconds pass ….

user> (realized? do-something)
true
user> @do-something
28
user> do-something
#<core$future_call$reify__6110@14c55ea: 28>

You can see that realized? is once again useful for when you don’t want to incur the blocking penalty and that you didn’t need to dereference do-something for the value to become realized.

Promise

Promises are used in a similar way to delay or future in that you dereference them for a value, can check if they have a value with realized? and they block when you dereference them if they don’t have a value until they do. Where they differ is that you don’t immediately give them a value, but provide them with one by calling deliver:

user> (def p (promise))
#'user/p
user> (realized? p)
false
user> (deliver p "as-promised")
#<core$promise$reify__6153@66650e56: "as-promised">
user> (realized? p)
true
user> @p
"as-promised"

Of course, calling @p will block the REPL until you open a new one and deliver it (provided you’re using swank or something that can have multiple open REPL threads). There are some really neat ways to combine the promise with future to get nice and declarative concurrency semantics. But I’ll leave that as an exercise for you.

I really enjoy how the dereferencing work exactly the same for future, delay and promise as they do for the Clojure atom and ref types.

Advertisements

From → Coding

Leave a Comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

%d bloggers like this: