If the values in the map don't change then why not just drop the map?
Implement the map as a function and memoize it eg (def f (memoize (fn [k]
(calc-value k
On Saturday, August 30, 2014 12:27:05 AM UTC-5, Colin Fleming wrote:
>
> Hi all,
>
> I want to use a map to cache values based on a k
Michał, that's quite a bit more straightforward, nice :) Also made me
realize that I should've used delays in synced-memoize.
Den tisdagen den 2:e september 2014 kl. 10:09:47 UTC+2 skrev Michał Marczyk:
>
> java.util.concurrent.ConcurrentHashMap has a putIfAbsent method that
> could be used wi
java.util.concurrent.ConcurrentHashMap has a putIfAbsent method that
could be used with delays to support this use case with a no
recomputation guarantee:
(def chm (java.util.concurrent.ConcurrentHashMap.))
;; this will work as expected whether chm has a value for :foo or not
(let [d (delay (+ 1
Forget about sleep, there's work to be done! I realized that the drawback I
mentioned with my solution, where concurrent calls to the memoized function
with different sets of arguments would be handled one-by-one, could easily
be resolved by having the cache inside synced-memoize store futures f
Huh, I gave it some more thought - of course, the reason why memoize won't
help us here is that there is no synchronization between simultaneous
invocations with the same set of arguments. This is typically not a problem
if the underlying function is fast, but in our case it would be neat with
I reckon if that worked, there would be no need for memoize anyway, but I
don't think swap! will allow for it. I'm far from an expert on swap! or
atoms, but several swap!s may be run simultaneously on a single atom (and
swap! may re-run the swapping function if the atom has been changed since
t
I believe you can replace:
(when-not (contains? @cache k)
(swap! cache assoc k (calc-value* k
with:
(swap! cache (fn [cache']
(if (contains? cache' k)
cache'
(assoc cache' k (calc-value* k)
Note: I haven't run this code
On Mon, Sep 1, 2
On inspecting the source for memoize, it would actually seem (to my eyes,
someone please correct me if I'm mistaken) to be using a similar approach
to what has been suggested earlier in the discussion, with the risk of
re-computing values at concurrent invocations with the same arguments. So
us
Indeed you're right, I was confused. The dosync call was a naive attempt to
avoid the CAS operation you were worried about earlier. I suppose another
option would be to use compare-and-set! with a lazy seq.
(compare-and-set! cache-atom (dissoc @cache-atom k) (assoc @cache-atom k
(lazy-seq (cons
Hey Colin,
That doesn't mean guava wouldn't be a nice solution here still. Just
.invalidateAll to purge it. Might even use softValues to let the gc decide
to remove some entries when running low on memory. Emulating a mutable
thing in clojure with an atom is not always better than using the mut
Hi Thomas,
Normally I'd agree with you, but in my case it actually works quite well
since I don't need to expire or worry about sizing. This is for caching
objects on IntelliJ parse tree elements, and the element with its cached
values is thrown away every time the document is parsed, so these are
Hi Marcus,
That's an interesting approach. My first reaction was that the update is
still not atomic, since you have:
(when-not (contains? @cache k)
(swap! cache assoc k (calc-value* k)))
Which I thought could cause different clients to see different values
depending on the race condition ther
Hi Beau,
I've not used the STM stuff at all, but my understanding is that dosync is
intended for co-ordinated updates to refs, and has no effect on atoms. It's
really intended for co-ordinating updates to multiple refs rather than as a
synchronisation primitive on a single entity. I might be wrong
As much as I like Clojure and atoms, I do not think they are a good fit for
caching. Not only is it impossible to address the concurrency issues
related to multiple threads loading the same object, but you also have to
do expiration and size management yourself. Immutability doesn't help much
f
How about something like this? You can still keep your cache as an atom
that you can pass around, and you avoid unnecessary recomputation through
memoize:
(def cache (atom {}))
(def lookup
(let [calc-value* (memoize calc-value)]
(fn [cache k]
(when-not (contains? @cache k)
(
I must be missing something, because this is too simple?
(defn get-maybe-cached [cache key]
(dosync
(if-let [v (get @cache key)]
v
(do
(reset! cache (assoc @cache key (calculate key)))
(get @cache key)
On Saturday, August 30, 2014
You are absolutely right. Sorry, for distraction. Deleted my message
immediately after I realized that, but it turns out it managed to go
already.
суббота, 30 августа 2014 г., 16:25:21 UTC+4 пользователь Colin Fleming
написал:
>
> I'm not sure I understand - the contention will be the same whe
I'm not sure I understand - the contention will be the same whether or not
the value is calculated in the swap! call, right? And if I calculate the
value and then pass the calculated value to swap!, that value will be
thrown away every time the cache contains an existing value for my key.
On 30
I see...
Just in case, I'd like to point out one possible deficiency in your
original snippet. Generally, it should be better move value calculation
outside of swap call, thus
reducing a chance of contention, especially when you have many threads
asking for different keys.
суббота, 30 август
In my case I can't use memoize because I need to supply the cache map -
that in turn is stored on another object so it can be invalidated by events
outside my control.
On 30 August 2014 20:00, Ray Miller wrote:
> On 30 August 2014 06:26, Colin Fleming
> wrote:
> >
> > I want to use a map to ca
Yes, in my case the update is atomic but doesn't strictly avoid
recomputation (since the Atom can call the calculation function many
times). I've given this some hammock time and I don't think that's a
problem. However on further investigation I do have to ensure that for each
of my keys the value
Oh, forget to wait for value in unwrap. Here is a better version
(defn unwrap [v]
(if-let [p (get v ::promise)]
@p
v))
(defn compute [cache k]
(let [p {::promise (promise)}
c (swap! cache assoc k p)
val (get c k)]
(when (identical? val p)
(let [result (calc
On 30 August 2014 06:26, Colin Fleming wrote:
>
> I want to use a map to cache values based on a key. I'm planning to use an
> atom for this. My basic operation is "give me the value for this key" - if
> the value exists in the map then that value should be returned, otherwise a
> new value should
Snippet you showed before is also not an atomic. If you want strictly to
avoid recomputations you need something more elaborate.
May be this
(def cache (atom {}))
(defn unwrap [v]
(if-let [a (get v ::atom)]
@a
v))
(defn compute [cache k]
(let [p {::atom (atom nil)}
c (swap
True, but only if you don't mind possibly calculating the value more than
once since the update is not atomic.
On 30 August 2014 18:31, Eldar Gabdullin wrote:
> Something like the following would be fine for me
>
> (def cache (atom {}))
>
> (defn lookup [cache k]
> (let [v (get @cache k ::nil
Something like the following would be fine for me
(def cache (atom {}))
(defn lookup [cache k]
(let [v (get @cache k ::nil)]
(if (= v ::nil)
(let [v (calc-value k)]
(swap! cache assoc k v)
v)
v)))
(let [value (lookup cache k)]
; use value and @cache here
)
Hi all,
I want to use a map to cache values based on a key. I'm planning to use an
atom for this. My basic operation is "give me the value for this key" - if
the value exists in the map then that value should be returned, otherwise a
new value should be calculated, inserted in the map and then ret
27 matches
Mail list logo