Threadlocal counter in Clojure

2019-01-25 13:27发布

问题:

I have a web app where i want to be able to track the number of times a given function is called in a request (i.e. thread).

I know that it is possible to do in a non-thread local way with a ref, but how would I go about doing it thread locally?

回答1:

There's a tool for this in useful called thread-local. You can write, for example, (def counter (thread-local (atom 0))). This will create a global variable which, when derefed, will yield a fresh atom per thread. So you could read the current value with @@counter, or increment it with (swap! @counter inc). Of course, you could also get hold of the atom itself with @counter and just treat it like a normal atom from then on.



回答2:

You can use a dynamic global var, bound to a value with binding in combination with the special form set! to change its value. Vars bound with binding are thread-local. The following will increase *counter* every time my-fn is called for any form called within a with-counter call:

(def ^{:dynamic true} *counter*)

(defmacro with-counter [& body]
  `(binding [*counter* 0]
     ~@body
     *counter*))

(defn my-fn []
  (set! *counter* (inc *counter*)))

To demonstrate, try:

(with-counter (doall (repeatedly 5 my-fn)))
;; ==> 5

For more information, see http://clojure.org/vars#set



回答3:

You can keep instance of ThreadLocal in ref. And every time you need to increase it just read value, increase it and set back. At the beginning of request you should initialize thread local with 0, because threads may be reused for different requests.