Skip to content

Instantly share code, notes, and snippets.

@ciniglio
Created January 17, 2015 19:52
Show Gist options
  • Save ciniglio/bf80f6ceb664f75032ae to your computer and use it in GitHub Desktop.
Save ciniglio/bf80f6ceb664f75032ae to your computer and use it in GitHub Desktop.
Clojure race condition
;; Original from
;; https://github.com/aphyr/prism/blob/d59aa8cc3b59b44f5241e53d452340bfc3936343/src/com/aphyr/prism.clj#L63
(defn slur
"Takes a unary function f, and a time in ms. Returns a function g such that
(g x) causes (f x) to be invoked unless (g x) had been invoked less than dt
ms ago."
[dt f]
; Maintain a map of args to invocation times.
(let [ts (atom {})]
(fn g [x]
(let [now (System/currentTimeMillis)
ts (swap! ts (fn [ts]
(let [prev (get ts x)]
(if (and prev (< (- now prev) dt))
ts
(assoc ts x now)))))
prev (get ts x)]
; If we're the first to call, or it's been longer than dt ms, call f.
(when (or (= now prev)
(<= dt (- now prev)))
(f x))))))
(defn my-slur
[dt f]
(let [ts (ref {})]
(fn g [x]
(when (dosync
(let [now (System/currentTimeMillis)
prev (get @ts x 0)
enough-time-has-passed (> (- now prev) dt)
ts (alter ts (fn [ts]
(if enough-time-has-passed
(assoc ts x now)
ts)))]
enough-time-has-passed))
(f x)))))
(defn test-slur [slur]
(let [a (atom [])
dt 10
f (fn [_] (swap! a #(conj % (System/currentTimeMillis))))
g (slur dt f)]
(doseq [x (range 1 10000)] (g 1))
(if (> (count @a) 1)
(let [diffs (reduce #(and %1 %2) (map (partial < dt)(map - (subvec @a 1) @a)))]
diffs)
a)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment