Clojure - Futures, Delays and Promises
Futures, Delays and Promises
Futures, delays and promises are easy, lightweight tools for concurrent programming. They allow us to separate task definition, task execution and requiring the result.
Futures
Futures are used to define a task and place it on another thread without requiring the result immediately.
1(future (Thread/sleep 4000)
2 (println "prints after 4 seconds"))
3(println "prints immediately")
When we want to get the result of a future task we can use the value that future macro
returns. That value is a reference value that we can use to request the result. We request
the result by dereferencing the future with eiter deref or @. Values of a future are
cached and dereferencing a future will block if the future hasn’t finished running.
1(let [result (future (println "this prints once")
2 (+ 1 1))]
3 (println "deref: " (deref result))
4 (println "@: " @result))
5; => this prints once
6; => deref: 2
7; => @: 2
We can pass additional arguments to deref to tell it a number of milliseconds to wait
along with the value to return if the call times out.
1(deref (future (Thread/sleep 1000) 0) 10 5)
2; => 5
realized? is used to chech if the future is done running.
Delays
Delays are used to define a task without having to execute it or require the result
immediately. They don’t evaluate until we request it by using force. Also the result
of a delay is cached like the result of future.
1(def hello-delay
2 (delay (println "Hello")
3 "Hello world"))
4
5(force hello-delay)
6; => Hello
7; => Hello world
8
9(force hello-delay)
10; => Hello world
Promises
A promise is a reference to a value that may not yet be realized, or computed. A promise is
created using the promise function, and its value can be set using deliver.
1(def p (promise))
2
3(defn compute-x []
4 (Thread/sleep 1000)
5 (deliver p 42))
6
7(compute-x)
8
9; block until p is delivered
10(println @p)