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, 2014 at 2:20 AM, Colin Fleming <colin.mailingl...@gmail.com> wrote: > 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 > pretty transient caches. In this particular case the calculation isn't too > heavyweight either so recalculating it in the unlikely event of contention > isn't a big deal. In fact, this discussion and the related thinking has > made me realise that my original solution was actually sufficient for my > somewhat strange use case, which is nice :-). For more typical server side > caching, I agree that Guava would be a great solution. > > Cheers, > Colin > > > On 1 September 2014 20:54, Thomas Heller <th.hel...@gmail.com> wrote: > >> 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 >> for caching either. There is core.cache that does some bits but I probably >> would recommend using something like CacheBuilder from the guava libs: >> >> See >> https://code.google.com/p/guava-libraries/ >> >> http://docs.guava-libraries.googlecode.com/git/javadoc/com/google/common/cache/CacheBuilder.html >> >> Its Java but the Clojure<->Java interop is so good that it doesn't matter >> much. >> >> On Saturday, August 30, 2014 7:27:05 AM UTC+2, Colin Fleming wrote: >>> >>> 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 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. >> > > -- > 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. > -- 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.