Skip to content

Instantly share code, notes, and snippets.

@adam-e-trepanier
Created December 12, 2014 04:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save adam-e-trepanier/f13a43bdfe0be6525152 to your computer and use it in GitHub Desktop.
Save adam-e-trepanier/f13a43bdfe0be6525152 to your computer and use it in GitHub Desktop.
(ns clojure-programming.concurrency.futures
(:import (java.util Date)))
;; Futures
;; Simple concept. Take some code and evaluate it in another thread. Thats it.
;; Futures return immediately, which allows the current thread of execution
;; to continue on doing its own thing. The results of the future can be
;; obtained by dereferencing the future. Note that if you try and dereference
;; the future prior to it being complete, it will block
;;
;; Below are two vars that generate futures. One for 3 seconds and another
;; for six
(def timeout-op
(future
(do
(Thread/sleep 3000)
"short op")
2000
:failed))
(def expensive-op
(future
(do
(Thread/sleep 6000)
"long op")))
;; If we require this namespace with a reload-all in the repl by doing
;; ) and try
;; to dereference expensive-op right away it will block. If you wait six
;; seconds and try again anytime after you will get the string.
;; The difference between delays and futures is that futures allow you to
;; specify a timeout and a value. If you try and dereference timeout-op
;; you will get the :failed keyword.
;; So where might a future be used.
;; Lets say we have an api that gets some patient information. And this patient
;; information has a :call_date. The call date is a long running calculation
;; to determine when a patient should be called on the phone. We could use
;; a future to get the :call_date if its not used right away. This would
;; allow us to move forward with the rest of the data processing and not block
;; on :call_date which would be offloaded to another thread.
(defn patient-info
[id]
{:name "John Doe"
:age 34
:call_date (future
(do
(Thread/sleep 2000)
(Date.)))})
;; So here when we call (patient-info 10) and assign to p it has
;; kicked off the :call_date processing into a another thread. This allows
;; us to continue on doing 'some other stuff' and when we finally need the
;; :call_date, in this case it will already be done processing.
(defn test-future
[]
(let [p (patient-info 10)]
(println "Patient name:"(p :name))
;; Do some other stuff
(Thread/sleep 3000)
(println "done computing")
(println "Call Date" @(p :call_date))))
;; Now go ahead and change the sleep value in patient-info to 6000 and run
;; test-future in the repl, you will notice now the future blocks because its
;; not done processing.
;; Futures in a nutshell
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment