Last active
October 24, 2017 15:40
-
-
Save fahrrad/e25f46e4407e53f5f93f6f7e93c8f2c6 to your computer and use it in GitHub Desktop.
This file contains 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 deal-picker.atoms-and-vars | |
(:require [clojure.set :as set])) | |
;; Vars are the normal way that you define symbolic names for values | |
(def ^:dynamic x 10) | |
(def some-fn (fn [x] (+ x 2))) | |
;; Beware, they are namespace global scoped, don't do this! | |
(defn my-double-sum [a b] | |
(let [x (+ a b)] | |
(def x (* 2 x)))) | |
;; This is how we can use vars in tests | |
(def ^:dynamic db | |
"DB2") | |
;; Redefs redefine the value a var is pointing to | |
(defn test-db-redefs [] | |
(println "DB is configured to be " db) | |
(with-redefs [db "Test DB"] | |
(dotimes [_ 3] | |
(Thread/sleep (+ 100 (rand-int 300))) | |
(println | |
(.getName (Thread/currentThread)) | |
" is connecting to " db)))) | |
;;; To be Thread safe, vars can be rebound per thread | |
(defn access-db [connect-to] | |
(binding [db connect-to] | |
(dotimes [_ 3] | |
(Thread/sleep (rand-int 300)) | |
(println | |
(.getName (Thread/currentThread)) | |
" is connecting to " db)))) | |
(defn test-access-db-thread [] | |
(.start (Thread. #(access-db "Postgres"))) | |
(.start (Thread. #(access-db "Oracle"))) | |
(.start (Thread. #(access-db "RDBMS")))) | |
;; Atoms are a way to share a global state over different threads. | |
;; They are suited for noncoordinated, synchronous action on shared state | |
;; Good use case for them is a counter: | |
(def counter (atom 0)) | |
(defn get-next-counter [] | |
(swap! counter inc)) | |
;; This is NOT a good use case: The action contains? has to be | |
;; eecuted before swap!. This is a operation that needs coordination | |
(def atom-cache (atom #{})) | |
(defn is-id-used-before-atom? [id] | |
(if (contains? @atom-cache id) | |
:error | |
(do (Thread/sleep (rand-int 1000)) | |
(swap! atom-cache conj id)))) | |
(defn start-thread-atom [] | |
(.start | |
(Thread. | |
#(dotimes [i 10] | |
(println | |
(.getName (Thread/currentThread)) | |
" checking id " i " : " (is-id-used-before-atom? i)))))) | |
(defn run-multiple-access-threads-atoms [] | |
(reset! atom-cache #{}) | |
(dotimes [_ 3] (start-thread-atom))) | |
;; That's where STM (software transactional memory) comes in. | |
;; Refs | |
;; This will gives us a construct: dosync that makes sure that | |
;; the value was not changed in between. If it did, it will rerun the transaction | |
(def cache (ref #{})) | |
(defn is-id-used-before? [id] | |
(dosync | |
(if (contains? @cache id) | |
:error | |
(do (Thread/sleep (rand-int 1000)) | |
(alter cache conj id))))) | |
(defn start-thread-ref [] | |
(.start (Thread. | |
#(dotimes [i 10] | |
(println | |
(.getName (Thread/currentThread)) | |
" checking id " i " : " (is-id-used-before? i)))))) | |
(defn run-multiple-access-threads-refs [] | |
(dosync (ref-set cache #{})) | |
(dotimes [_ 3] (start-thread-ref))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment