Skip to content

Instantly share code, notes, and snippets.

@lnostdal
Last active July 13, 2024 16:58
Show Gist options
  • Save lnostdal/1fbd9b3d2ddc7bff1830638ea88348cc to your computer and use it in GitHub Desktop.
Save lnostdal/1fbd9b3d2ddc7bff1830638ea88348cc to your computer and use it in GitHub Desktop.
Clojure: Performance of with-local-vars vs. atom vs. volatile vs. unsynchronized-mutable field
;; Performance of with-local-vars vs. atom vs. volatile vs. unsynchronized-mutable field.
(definterface IOObject
(setVal [new-val])
(getVal [])
(oswap [f])
(oswap [f x])
(oswap [f x y])
(oswap [f x y z]))
(deftype OObject
[^:unsynchronized-mutable val]
IOObject
(setVal [o new-val] (set! val new-val))
(getVal [o] val)
(oswap [o f] (set! val (f val)))
(oswap [o f x] (set! val (f val x)))
(oswap [o f x y] (set! val (f val x y)))
(oswap [o f x y z] (set! val (f val x y z)))
clojure.lang.IDeref
(deref [o] val))
(defn blah []
(with-local-vars [wlv 0]
(time
(dotimes [i 100000000]
(var-set wlv (inc ^long (var-get wlv)))))
(println @wlv)))
;; "Elapsed time: 9574.548806 msecs"
(defn blah []
(let [a (atom 0)]
(time
(dotimes [i 100000000]
(swap! a (fn [^long val] (inc val)))))
(println @a)))
;; "Elapsed time: 1908.351393 msecs"
(defn blah []
(let [v (volatile! 0)]
(time
(dotimes [i 100000000]
(vswap! v (fn [^long val] (inc val)))))
(println @v)))
;; "Elapsed time: 1000.284472 msecs"
(defn blah []
(let [o (OObject. 0)]
(time
(dotimes [i 100000000]
(.oswap o (fn [^long val] (inc val)))))
(println @o)))
;; "Elapsed time: 437.329174 msecs"
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;; You can combine this into "bash in-place" (sort of) Clojure transients:
(defn blah1 []
(let [x (OObject. {})]
(dotimes [i 50000000]
(.setVal x (assoc (.getVal x) :a (* i i))))
(.getVal x)))
(defn blah2 []
(let [x (OObject. (transient {}))]
(dotimes [i 50000000]
(.setVal x (assoc! (.getVal x) :a (* i i))))
(persistent! (.getVal x))))
quantataraxia.core> (loop []
(println "blah1:")
(time (blah1))
(newline)
(println "blah2:")
(time (blah2))
(newline)
(recur))
blah1:
"Elapsed time: 1267.678723 msecs"
blah2:
"Elapsed time: 533.646835 msecs"
blah1:
"Elapsed time: 1270.494604 msecs"
blah2:
"Elapsed time: 524.925682 msecs"
blah1:
"Elapsed time: 1199.423884 msecs"
blah2:
"Elapsed time: 488.822583 msecs"
blah1:
"Elapsed time: 1186.578578 msecs"
blah2:
"Elapsed time: 536.999552 msecs"
;; ~60% improvement
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment