Skip to content

Commit b655e5b

Browse files
committed
Merge pull request #22 from arrdem/patch-1
Implement a better memoize for parallel use cases
2 parents 0e5c39f + 77356d7 commit b655e5b

File tree

1 file changed

+31
-0
lines changed

1 file changed

+31
-0
lines changed

src/flatland/useful/parallel.clj

+31
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,34 @@
1717
(let [body (wrap-fn #(doall (map f slice)))]
1818
(future-call body)))
1919
(slice *pcollect-thread-num* coll))))))
20+
21+
22+
(defn- assoc-noclobber
23+
"An assoc wrapper which ensures that existing keys will not be
24+
clobbered by subsequent assoc invocations.
25+
26+
Used as a helper for locking-memoize to ensure that (delay) refs
27+
cannot be lost by swap! retry behavior."
28+
29+
[m k v]
30+
(if (contains? m k) m
31+
(assoc m k v)))
32+
33+
(defn pmemoize
34+
"Memoizes the function f, using the same approach as
35+
clojure.core/memoize. The practical difference is that this function
36+
provides the gurantee that in spite of parallel invocations of the
37+
memoized function each input to f will only ever be memoized
38+
once. This resolves an implementation detail in clojure.core/memoize
39+
which allows f to be applied to args without locking the cache to
40+
prevent other threads duplicating the work."
41+
42+
[f]
43+
(let [mem (atom {})]
44+
(fn [ & args ]
45+
(if-let [e (find @mem args)]
46+
(deref (val e))
47+
(-> (swap! mem assoc-noclobber
48+
args (delay (apply f args)))
49+
(get args)
50+
(deref))))))

0 commit comments

Comments
 (0)