Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

binding & pmap interaction change?

There are several somewhat old blog posts out there advising caution when mixing dynamic variables, binding, and pmap, e.g. here, where we get the following code snippet:

user=> (def *foo* 5)
#'user/*foo*
user=> (defn adder
             [param]
             (+ *foo* param))
#'user/adder
user=> (binding [*foo* 10]
         (doseq [v (pmap adder (repeat 3 5))]
           (println v)))
10
10
10
nil

But that's not what happens when I run that code (changing the first line to (def ^:dynamic *foo* 5)). I get three 15s as output (using Clojure 1.4), just as you would naïvely expect—that is, with the change in the binding form seen by the function passed to pmap. Have the way thread-local bindings and pmap interact changed? I can't find this documented anywhere.

like image 476
ben w Avatar asked Aug 24 '12 21:08

ben w


1 Answers

starting in 1.3 the set of local bindings are sent to pmap along with the function. So as long as you mark the var ^:dynamic this is no longer a problem. This feature it called Binding Conveyance and is included in the 1.3 changelog:

from: https://github.com/clojure/clojure/blob/1.3.x/changes.txt

Clojure APIs that pass work off to other threads (e.g. send, send-off, pmap, future) now convey the dynamic bindings of the calling thread:

  (def ^:dynamic *num* 1)
  (binding [*num* 2] (future (println *num*)))
  ;; prints "2", not "1"
like image 137
Arthur Ulfeldt Avatar answered Sep 23 '22 04:09

Arthur Ulfeldt