Understanding Clojure Concurrency Example

I just go through the various documentation on Clojure concurrency and switched to an example on the website (http://clojure.org/concurrent_programming).

(import '(java.util.concurrent Executors)) (defn test-stm [nitems nthreads niters] (let [refs (map ref (replicate nitems 0)) pool (Executors/newFixedThreadPool nthreads) tasks (map (fn [t] (fn [] (dotimes [n niters] (dosync (doseq [r refs] (alter r + 1 t)))))) (range nthreads))] (doseq [future (.invokeAll pool tasks)] (.get future)) (.shutdown pool) (map deref refs))) 

I understand what it does and how it works, but I don’t understand why the second anonymous function fn [] is needed?

Many thanks,

Dusha.

PS Without this second fn [], I get a NullPointerException.

+6
concurrency clojure
source share
2 answers

Here is a classic example of using higher order functions:

 ;; a function returns another function (defn make-multiplyer [times] (fn [x] (* x times))) ;; now we bind returned function to a symbol to use it later (def multiply-by-two (make-multiplyer 2)) ;; let use it (multiply-by-two 100) ; => 200 

In this code example, fn inside fn works the same. When map invokes (fn [t] (fn [] ...)), it gets the internal fn.

 (def list-of-funcs (map (fn [t] (fn [] (* t 10))) ; main part (range 5))) ;; Nearly same as ;; (def list-of-funcs (list (fn [] (* 0 10)) ;; (fn [] (* 1 10)) ;; ... ;; (fn [] (* 4 10)))) (for [i list-of-funcs] (i)) ; => (0 10 20 30 40) 

Update. And as Alex said, the tasks in the code sample are tied to a list of calls, which are then passed to .invokeAll ().

+5
source share

The first fn is what the map uses to create seq from fn - one for each thread. This is because tasks are a series of functions! The .invokeAll () method expects a collection of Callables functions (Clojure implements the Callable interface)

from Clojure.org: special forms

fns implements the Java Callable, Runnable, and Comparator interfaces.

+2
source share

All Articles