Clojure provides a lot of different facilities to handle concurrency. One of
these are Vars. They can be used to store thread-local information, eg. with
binding. A different thread cannot see the value „modified“ with
And exactly there lies the rub…
Let's start with some setup, which we can use later on.
(def *increment* 1) (defn incr [x] (+ x *increment*))
This is basically a function similar to
inc which increments a given number.
inc it provides a knob by which we can change the increment step.
So. Now let's try our function.
user=> (map incr [1 2 3]) (2 3 4)
Ok. Nothing exciting so far. But now let's play with our knob. We use
to change the value of
user=> (binding [*increment* 3] (doall (map incr [1 2 3]))) (4 5 6)
Yeah! It works!
As I said in the introductory paragraph: Clojure provides several facilities
to handle concurrency. Besides Vars there is for example
basically a drop-in replacement for
map which distributes the computation
of the output seq on several threads. So each
map can be easily turned to
parallel construct by simply adding a single character. (Whether this makes
sense in every case is a different question!)
So, let's try
pmap for fun and profit!
user=> (binding [*increment* 3] (doall (pmap incr [1 2 3]))) (2 3 4)
Huh? Argh! We got caught by the thread-localness of Vars. The changed value
*increment* established with
binding is not carried over to the new
thread, where the actual computation is done. There the root binding is in
effect and we get the original value of
To fix this situation we could take a hands-down approach and simply re-establish the binding in the target thread.
user=> (binding [*increment* 3] (doall (pmap (let [step *increment*] (fn [x] (binding [*increment* step] (incr x)))) [1 2 3]))) (4 5 6)
This looks a bit silly, but imagine the
binding being somewhere else
in the code in a real-world project. So what do we do? We capture the
thread-local binding in a local and pass a closure to
pmap. This closure
sets up the binding on the new thread before invocing
This works but is quite a bit of tedious boilerplate. But luckily Clojure provides a helper utility for this scenario!
user=> (binding [*increment* 3] (doall (pmap (bound-fn [x] (incr x)) [1 2 3]))) (4 5 6)
bound-fn defines a function – similar to
fn. However with the difference
that it restores any thread-local bindings before executing the body of the
function. So it is basically an extended approach to the above
In our case we can simplify things even more: we already have a function. We
should be able to turn this function into a different one with the desired
properties – similar to how
memoize works. And in fact we can do that!
user=> (binding [*increment* 3] (doall (pmap (bound-fn* incr) [1 2 3]))) (4 5 6)
A combination of Vars and
binding can be a way to modify the environment
of the code, eg. by rebinding
*out*. However one has to take care when
crossing thread boundaries. The
bound-fn* utilities help
in such a situation.
bindingbinds in parallel, while
doalls. Why this is necessary is explained in a previous post.
Published by Meikel Brandmeyer on .