Created
December 12, 2014 04:24
-
-
Save adam-e-trepanier/f13a43bdfe0be6525152 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(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