Hey Aria, If you really want a mutable Counter, IMO you might as well do things your "Java" way with a HashMap ... or at least that's how I would do it.
A more Clojure way would be a totally safe, functional counter: (deftype ClojureCounter2 [counts total] Counter (getCount [k] (get counts k 0.0)) (incCount! [k v] (ClojureCounter2. (assoc counts k (+ v (get counts k 0.0))) (+ total v))) (totalCount [] total)) (defn make-cc2 [] (ClojureCounter2 {} 0.0)) And, by my measurements, it's twice as fast as your mutable Clojure version when run in the following harness: (defn testFunctionalCounter [counter] (let [r (java.util.Random. 0)] (loop [counter counter i (int 1000000)] (when-not (== i (int 0)) (recur (incCount! counter (.nextInt r 100000) (.nextDouble r)) (dec i)))))) If you want to keep to a functional style but don't care if old copies of the counter get trashed (be careful!), you can easily switch to transients: (deftype ClojureCounter3 [counts total] Counter (getCount [k] (get counts k 0.0)) (incCount! [k v] (ClojureCounter3. (assoc! counts k (+ v (get counts k 0.0))) (+ total v))) (totalCount [] total)) (defn make-cc3 [] (ClojureCounter3 (transient {}) 0.0)) which gives you another > 2x speedup, bringing it to within ~50% of the Java version. HTH, Jason On Feb 17, 2:40 am, aria42 <ari...@gmail.com> wrote: > Hi all, I was playing with the defprotocol/deftype/reify stuff in 1.2, > and I wanted to test how a common abstraction I use would look if I > did with java data structures vs. clojure ones. I've pasted the code > below. I'll wait for you to take a look....So on my test, I have the > Clojure version about 5x slower than the Java one only one cpu. Now I > know that JavaMapCounter isn't thread safe, while ClojureCounter is, > and that if I had sufficiently many cpus, the clojure version would be > faster. But is there a better way to do what I'm doing with clojure to > get the performance a bit more up to par with javas? > > Thanks, Aria > > (defprotocol Counter > (getCount [_ k]) > (incCount! [_ k v]) > (totalCount [_])) > > (defn JavaMapCounter [] > (let [counts (java.util.HashMap.) > total (org.apache.commons.lang.mutable.MutableDouble.)] > (reify :as self > Counter > (getCount [k] (.get counts k)) > (incCount! [k v] > (let [cur-v (if-let [x (getCount self k)] x 0.0)] > (.put counts k (+ v cur-v))) > (.setValue total (+ (.doubleValue total) v))) > (totalCount [] (.doubleValue total))))) > > (defn ClojureCounter [] > (let [state (atom {:counts (hash-map) :total 0.0})] > (reify :as self > Counter > (getCount [k] (if-let [x (get-in @state [:counts,k])] x 0.0)) > (incCount! [k v] > (swap! state > (fn [data] > (let [add-v (fn [x] (if x (+ x v) v))] > (-> data (update-in [:counts,k] add-v) > (update-in [:total] add-v)))))) > (totalCount [] (:total @state))))) > > (defn testCounter [counter] > (let [r (java.util.Random. 0)] > (dotimes [_ 1000000] > (incCount! counter (.nextInt r 100000) (.nextDouble r))))) > > (time (testCounter (JavaMapCounter))) > (time (testCounter (ClojureCounter))) -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en