This page is no longer maintained — Please continue to the home page at www.scala-lang.org

Your approach to caching

2 replies
pkolaczk
Joined: 2010-01-14,
User offline. Last seen 2 years 38 weeks ago.

Hi,

I often want to cache results of functions.
For functions without arguments it is easy - just use lazy val.
But I'm interested what is the best method to cache the results in case
of functions with arguments.

I do something like this:

var cache = collection.mutable.Map[(A1, A2), R]()

def cachedFunction(a1: A1, a2: A2): R = {
cache.getOrElseUpdate((a1, a2), {

// body of the function

}
}

Is there any better way?
Is it thread safe? If not, is there any better way that would be
thread-safe?

Regards,
Piotr Kołaczkowski

Jason Zaugg
Joined: 2009-05-18,
User offline. Last seen 38 weeks 5 days ago.
Re: Your approach to caching

Hi Piotr,

I haven't found a safe way to do this with the standard Scala or Java
concurrent maps without requiring a global lock on the entire map. (I
would be very happy to be corrected, though!)

For starters, you need to use a ConcurrentMap, not
collection.mutable.Map. JavaConversions.JConcurrentMapWrapper
implements this interface. But it doesn't override
MapLike#getOrElseUpdate, which makes sense because Java ConcurrentMap
interface only provides the following method, which isn't lazy in the
value:

public interface ConcurrentMap extends Map {
V putIfAbsent(K key, V value);
// ...
}

This is solved with a computing concurrent hash map from Google Guava
collections, which threadsafe, uses granular locks, and ensures that
each calculation is only performed once.

On top of this, I use scalaz.Memo which lets you abstract over the
memoization strategy.

It works roughly like this: http://gist.github.com/458558

-jason

2010/6/30 Piotr Kołaczkowski :
> I often want to cache results of functions.
> For functions without arguments it is easy - just use lazy val.
> But I'm interested what is the best method to cache the results in case of
> functions with arguments.

> Is there any better way?
> Is it thread safe? If not, is there any better way that would be
> thread-safe?

ounos
Joined: 2008-12-29,
User offline. Last seen 3 years 44 weeks ago.
Re: Your approach to caching


2010/6/30 Jason Zaugg <jzaugg [at] gmail [dot] com>
Hi Piotr,

I haven't found a safe way to do this with the standard Scala or Java
concurrent maps without requiring a global lock on the entire map. (I
would be very happy to be corrected, though!)

http://guava-libraries.googlecode.com/svn/trunk/javadoc/com/google/common/collect/MapMaker.html  

For starters, you need to use a ConcurrentMap, not
collection.mutable.Map. JavaConversions.JConcurrentMapWrapper
implements this interface. But it doesn't override
MapLike#getOrElseUpdate, which makes sense because Java ConcurrentMap
interface only provides the following method, which isn't lazy in the
value:

 public interface ConcurrentMap<K, V> extends Map<K, V> {
   V putIfAbsent(K key, V value);
   // ...
 }

This is solved with a computing concurrent hash map from Google Guava
collections, which threadsafe, uses granular locks, and ensures that
each calculation is only performed once.

On top of this, I use scalaz.Memo which lets you abstract over the
memoization strategy.

It works roughly like this: http://gist.github.com/458558

-jason

2010/6/30 Piotr Kołaczkowski <pkolaczk [at] elka [dot] pw [dot] edu [dot] pl>:
> I often want to cache results of functions.
> For functions without arguments it is easy - just use lazy val.
> But I'm interested what is the best method to cache the results in case of
> functions with arguments.

> Is there any better way?
> Is it thread safe? If not, is there any better way that would be
> thread-safe?

Copyright © 2012 École Polytechnique Fédérale de Lausanne (EPFL), Lausanne, Switzerland