Skip to content

Commit

Permalink
Merge pull request #22 from arrdem/patch-1
Browse files Browse the repository at this point in the history
Implement a better memoize for parallel use cases
  • Loading branch information
amalloy committed Oct 10, 2014
2 parents 0e5c39f + 77356d7 commit b655e5b
Showing 1 changed file with 31 additions and 0 deletions.
31 changes: 31 additions & 0 deletions src/flatland/useful/parallel.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,34 @@
(let [body (wrap-fn #(doall (map f slice)))]
(future-call body)))
(slice *pcollect-thread-num* coll))))))


(defn- assoc-noclobber
"An assoc wrapper which ensures that existing keys will not be
clobbered by subsequent assoc invocations.
Used as a helper for locking-memoize to ensure that (delay) refs
cannot be lost by swap! retry behavior."

[m k v]
(if (contains? m k) m
(assoc m k v)))

(defn pmemoize
"Memoizes the function f, using the same approach as
clojure.core/memoize. The practical difference is that this function
provides the gurantee that in spite of parallel invocations of the
memoized function each input to f will only ever be memoized
once. This resolves an implementation detail in clojure.core/memoize
which allows f to be applied to args without locking the cache to
prevent other threads duplicating the work."

[f]
(let [mem (atom {})]
(fn [ & args ]
(if-let [e (find @mem args)]
(deref (val e))
(-> (swap! mem assoc-noclobber
args (delay (apply f args)))
(get args)
(deref))))))

0 comments on commit b655e5b

Please sign in to comment.