Futures, Promises, and Delays
Prerequisites: Atoms
Three small tools for work that happens later or elsewhere. All three
are read with deref / @.
future — run in another thread
(defn fetch [name ms]
(Thread/sleep ms)
(str name " data"))
(let [start (System/currentTimeMillis)
users (future (fetch "users" 300))
orders (future (fetch "orders" 300))]
(println @users "+" @orders)
(println "parallel:" (< (- (System/currentTimeMillis) start) 550)))
(def slow (future (Thread/sleep 5000) :done))
(println (deref slow 100 :timed-out))
(println (realized? slow))
(future-cancel slow)
(shutdown-agents)
users data + orders data
parallel: true
:timed-out
false
futureruns its body on a thread pool and returns immediately.@fblocks until the result is ready;(deref f timeout-ms default)waits at most that long.- Two 300 ms tasks together took about 300 ms, not 600.
promise — a value delivered later
(def answer (promise))
(future
(Thread/sleep 100)
(deliver answer 42))
(println "waiting...")
(println "got" @answer)
(deliver answer 99) ; ignored: a promise is delivered once
(println @answer)
(shutdown-agents)
waiting...
got 42
42
A promise is an empty box that one thread fills with deliver and
others wait on.
delay — compute once, on demand
(def config
(delay
(println "(loading config)")
{:db "postgres://localhost/app"}))
(println "started")
(println (realized? config))
(println (:db @config))
(println (:db @config))
started
false
(loading config)
postgres://localhost/app
postgres://localhost/app
The body runs the first time the delay is dereferenced, and the result is cached — ideal for expensive resources that might not be needed.
pmap
(defn slow-square [n] (Thread/sleep 100) (* n n))
(let [start (System/currentTimeMillis)
result (doall (pmap slow-square (range 8)))]
(println result)
(println "faster than sequential:" (< (- (System/currentTimeMillis) start) 700)))
(shutdown-agents)
(0 1 4 9 16 25 36 49)
faster than sequential: true
pmap is a parallel map — worthwhile only when each item takes a
noticeable amount of work, since coordinating threads has a cost.