Last active
March 31, 2018 11:33
-
-
Save BadUncleX/7fbac99fcabb8a64fc71fb0020e24e4a to your computer and use it in GitHub Desktop.
STM usage ref and dosync (alter , commute, ensure)
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
(def total-donations (ref 0)) | |
(def count-donations (ref 0)) | |
;; start 9 people collecting money | |
(comment | |
(dotimes [_ 9] | |
(doto (Thread. (fn [] | |
;; go collect $10 | |
;; ... | |
(dosync | |
;; record $10 | |
(alter total-donations + 10) | |
;; record one donation | |
(alter count-donations inc)) | |
;; do it again | |
(recur))) | |
.start))) | |
;; start one person tweeting the total | |
(comment | |
(doto (Thread. (fn [] | |
;; wait 100 seconds | |
(Thread/sleep 10000) | |
(println (str "We collected $" @total-donations " total!")))) | |
.start)) | |
;; start one person tweeting the average | |
(comment | |
(doto (Thread. (fn [] | |
;; wait 100 seconds | |
(Thread/sleep 10000) | |
(when (pos? @count-donations) | |
(println (str "Average donation: $" (double (dosync (/ @total-donations @count-donations)))))))) | |
.start)) |
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
;; dosync with alter | |
(def makoto-account (ref {:name "Makoto Hashimoto" :amount 1000})) | |
(def nico-account (ref {:name "Nicolas Modrzyk" :amount 2000})) | |
(defn transfer! [from to amount] | |
(dosync (println "transfer money from " (:name @from) " to " (:name @to) " amount = " amount " begins") | |
(alter from assoc :amount (- (:amount @from) amount)) | |
(Thread/sleep 500) (alter to assoc :amount (+ (:amount @to) amount)) | |
(println "Now, " (:name @from) " amount is " (:amount @from) " and " (:name @to) " amount is " (:amount @to)) )) | |
(comment | |
(transfer! makoto-account nico-account 10)) | |
(comment | |
(do | |
(future (transfer! makoto-account nico-account 200)) | |
(future (transfer! makoto-account nico-account 300)))) | |
;; 使用ensure按序执行,不用竞争 | |
;; 这不就是加锁么? | |
;; No, 还保证只允许在dosync的transaction之下运行, 直接reset不允许. | |
(defn ensure-transfer! [from to amount] | |
(dosync (ensure from) | |
(println "transfer money from " (:name @from) " to " (:name @to) " amount = " amount " begins") | |
(alter from assoc :amount (- (:amount @from) amount)) | |
(Thread/sleep 500) | |
(alter to assoc :amount (+ (:amount @to) amount)) | |
(println "Now, " (:name @from) " amount is " (:amount @from) " and " (:name @to) " amount is " (:amount @to)))) | |
(comment | |
(do | |
(future (ensure-transfer! nico-account makoto-account 100)) | |
(future (ensure-transfer! nico-account makoto-account 200)))) | |
;; add watcher for ref | |
;; | |
(defn add-watcher [ref] | |
(add-watch ref :watcher | |
(fn [_ _ old-state new-state] | |
(prn "---- ref changed --- " old-state " => " new-state) ))) | |
(add-watcher makoto-account) | |
(add-watcher nico-account) | |
(defn refined-transfer! [from to amount] | |
(dosync (ensure from) | |
(if (<= (- (:amount @from) amount) 0) | |
(throw (Exception. "insufficient amount"))) | |
(alter from assoc :amount (- (:amount @from) amount)) | |
(Thread/sleep 500) | |
(alter to assoc :amount (+ (:amount @to) amount)))) | |
;;Let's set values of refs using ref-set: | |
(comment | |
(do (ref-set makoto-account {:name "Makoto Hashimoto" :amount 1000}) | |
(ref-set nico-account {:name "Nicolas Modrzyk" :amount 2000})) ) | |
;;=> IllegalStateException No transaction running | |
(comment | |
(dosync (ref-set makoto-account {:name "Makoto Hashimoto" :amount 1000}) | |
(ref-set nico-account {:name "Nicolas Modrzyk" :amount 2000}) | |
)) | |
;; let's test concurrently | |
(comment | |
(do | |
(future (refined-transfer! makoto-account nico-account 100)) | |
(future (refined-transfer! nico-account makoto-account 300)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment