What is Futures in Clojure
The future is a macro defined in clojure.core, one of concurrency primitives. This macro create a future object for a body of expression. The future object is a Reference Type, you can dereference it later by deref or @.
user> (def futureobj (future (println "In future") (* 2 10))) In future #'user/futureobj user> @futureobj 20 user> (deref futureobj) 20 user>
The expression body of the future will be executed in a new thread right after the creation of the future object and the result will be cached when thread complete. If the body expression takes a while to complete, then the deref will be blocked until the thread complete.
From above code, we can see the message is printed when the future object is created, but later deref won't print the message, because the thread has finished, and the result is cached, deref can get the result immediately.
We can take advantage of this feature to simulate a thread pool whenever we need a bunch of threads and throw some tasks into it.
Another commonly used method is agent, every agent has an action queue, those actions will be executed one by one in a thread, we can simply create a bunch of agents and send just one action to each agent.
As you will see, its so easy and light weight and simple to create threads in Clojure. You should do it whenever possible.
In the following example we create 10 threads , each thread execute a task:
; agent based thread pool (doseq [i (range 0 10)] (send-off (agent i) my-action) ) ; future based thread pool (doall (map #(deref %) (doall (map #(future (my-action %) (range 0 10))))))
Whats the difference between the two methods? The first method, task threads run on its own, the main program has no control of it. The second way, main program will block until all thread terminated, we can set a callback function that will be triggered right after all tasks completed. This is very useful in some circumstances.