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 августа 2014 г., 14:09:42 UTC+4 пользователь Colin Fleming написал: > > 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 that is returned is identical since it uses identity > equality semantics, so I might have to stick with my original solution. > Thanks for the input though, it's very interesting to see your solution. > > > On 30 August 2014 19:54, Eldar Gabdullin <elda...@gmail.com <javascript:>> > wrote: > >> 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! cache assoc k p) >> >> val (get c k)] >> (when (identical? val p) >> >> (swap! (::atom p) (fn [_] (calc-value k))) >> >> (swap! cache assoc k @(::atom p))) >> >> (unwrap val))) >> >> (defn lookup [cache k] >> >> (let [v (get @cache k ::nil)] >> >> (if (= v ::nil) >> >> (compute cache k) >> (unwrap v)))) >> >> >> >> суббота, 30 августа 2014 г., 11:18:51 UTC+4 пользователь Colin Fleming >> написал: >>> >>> 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 <elda...@gmail.com> wrote: >>> >>>> 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 >>>> ) >>>> >>>> >>>> суббота, 30 августа 2014 г., 9:27:05 UTC+4 пользователь Colin Fleming >>>> написал: >>>> >>>>> 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 >>>>> returned. My plan is to implement something like the following: >>>>> >>>>> >>>>> (defn ensure [cache key] (if (contains? cache key) cache (assoc >>>>> cache key (calc-value key))))(let [value (get (swap! cache ensure key) >>>>> key)] ... do my thing with value ...) >>>>> >>>>> >>>>> So 'ensure' ensures that the cache contains the value for key, the >>>>> swap! operation returns the cache with the value and then I get it out. >>>>> This works but feels a little clumsy, is there a better way to do this? >>>>> >>>>> Also, looking at the Atom source code, I see that this will cause a >>>>> CAS operation even if the value returned from swap! is identical to the >>>>> original value. It seems like a reasonable optimisation would be to check >>>>> if the values are identical and not update if so - is there a reason this >>>>> might not be a good idea? >>>>> >>>>> Thanks, >>>>> Colin >>>>> >>>> -- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To post to this group, send email to clo...@googlegroups.com >>>> >>>> Note that posts from new members are moderated - please be patient with >>>> your first post. >>>> To unsubscribe from this group, send email to >>>> clojure+u...@googlegroups.com >>>> >>>> For more options, visit this group at >>>> http://groups.google.com/group/clojure?hl=en >>>> --- >>>> You received this message because you are subscribed to the Google >>>> Groups "Clojure" group. >>>> To unsubscribe from this group and stop receiving emails from it, send >>>> an email to clojure+u...@googlegroups.com. >>>> >>>> For more options, visit https://groups.google.com/d/optout. >>>> >>> >>> -- >> You received this message because you are subscribed to the Google >> Groups "Clojure" group. >> To post to this group, send email to clo...@googlegroups.com >> <javascript:> >> Note that posts from new members are moderated - please be patient with >> your first post. >> To unsubscribe from this group, send email to >> clojure+u...@googlegroups.com <javascript:> >> For more options, visit this group at >> http://groups.google.com/group/clojure?hl=en >> --- >> You received this message because you are subscribed to the Google Groups >> "Clojure" group. >> To unsubscribe from this group and stop receiving emails from it, send an >> email to clojure+u...@googlegroups.com <javascript:>. >> For more options, visit https://groups.google.com/d/optout. >> > > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.