- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Your approach to caching
Wed, 2010-06-30, 12:42
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
Wed, 2010-06-30, 13:27
#2
Re: Your approach to caching
2010/6/30 Jason Zaugg <jzaugg@gmail.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@elka.pw.edu.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?
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?