2010-09-06 13 views
21

This page tiene una descripción del método getOrElseUpdate el uso del Mapa:¿Cómo almacenar en caché los resultados en scala?

object WithCache{ 
    val cacheFun1 = collection.mutable.Map[Int, Int]() 
    def fun1(i:Int) = i*i 
    def catchedFun1(i:Int) = cacheFun1.getOrElseUpdate(i, fun1(i)) 
} 

esta manera puede utilizar catchedFun1 que comprobará si contiene cacheFun1 valor de la clave y el retorno asociado a él. De lo contrario, invocará fun1, luego cacheará el resultado cacheFun1, luego devolverá el resultado fun1.

Puedo ver un peligro potencial - cacheFun1 puede ser demasiado grande. ¿Entonces el recolector de basura debe limpiar de alguna manera cacheFun1?

P.S. ¿Qué hay de scala.collection.mutable.WeakHashMap and java.lang.ref.*?

+3

Probablemente: http: // www. codeinstructions.com/2008/09/weakhashmap-is-not-cache-understanding.html – Debilski

Respuesta

6

En la lista de correo de scala ellos sometimes apuntan a MapMaker en el Google collections library. Es posible que desee echar un vistazo a eso.

+4

Google Collections se ha renombrado como Guava, y el nuevo CacheBuilder probablemente sea una coincidencia más cercana: http: //docs.guava-libraries.googlecode. com/git/javadoc/index.html? com/google/common/cache/CacheBuilder. html –

16

Vea el Memo pattern y el Scalaz implementation de dicho papel.

Consulte también una implementación de STM como Akka.

No es que esto es sólo el almacenamiento en caché local, lo que podría querer a lookinto una memoria caché distribuida o como STMCCSTM, Terracotta o Hazelcast

+1

Solo que el * Memo Pattern * usa 'WeahHashMap' y por lo tanto no es un muy buen caché. – Debilski

+2

@Debilski Depende de los requisitos de "caché". En este caso, un "caché débil" funciona para elevar las preocupaciones de los carteles de que "cacheFun1 puede [convertirse en demasiado] grande". –

2

Puesto que no se ha mencionado antes de que me puso sobre la mesa la luz Spray-Caching que se puede usar independientemente de Spray y proporciona estrategias de desahucio de tamaño esperado, tiempo de vida y tiempo de inactividad.

7

Echa un vistazo a la caché de aerosol (super fácil de usar)

http://spray.io/documentation/1.1-SNAPSHOT/spray-caching/

hace el trabajo fácil y tiene algunas características interesantes

por ejemplo:

 import spray.caching.{LruCache, Cache} 

     //this is using Play for a controller example getting something from a user and caching it 
     object CacheExampleWithPlay extends Controller{ 

     //this will actually create a ExpiringLruCache and hold data for 48 hours 
     val myCache: Cache[String] = LruCache(timeToLive = new FiniteDuration(48, HOURS)) 

     def putSomeThingInTheCache(@PathParam("getSomeThing") someThing: String) = Action { 
      //put received data from the user in the cache 
      myCache(someThing,() => future(someThing)) 
      Ok(someThing) 
     } 

     def checkIfSomeThingInTheCache(@PathParam("checkSomeThing") someThing: String) = Action { 
      if (myCache.get(someThing).isDefined) 
      Ok(s"just $someThing found this in the cache") 
      else 
      NotFound(s"$someThing NOT found this in the cache") 
     } 
     } 
2

Para sencilla las necesidades de almacenamiento en caché, todavía estoy usando Guava cache solution en Scala también. Ligero y probado en batalla.

Si Fit sus necesidades y limitaciones en general describen a continuación, podría ser una buena opción:

  • dispuesto a gastar algo de memoria para mejorar la velocidad.
  • Esperando que las claves a veces se hagan más de una consulta.
  • Su caché no necesitará almacenar más datos que los que caben en la memoria RAM. (Las memorias caché de Guava son locales para una única ejecución de su aplicación. No almacenan datos en archivos ni en servidores externos.)

ejemplo de uso que será algo como esto:

lazy val cachedData = CacheBuilder.newBuilder() 
    .expireAfterWrite(60, TimeUnit.MINUTES) 
    .maximumSize(10) 
    .build(
     new CacheLoader[Key, Data] { 
     def load(key: Key): Data = { 
      veryExpansiveDataCreation(key) 
     } 
     } 
    ) 

Para leer de él, se puede usar algo como:

def cachedData(ketToData: Key): Data = { 
    try { 
     return cachedData.get(ketToData) 
    } catch { 
     case ee: Exception => throw new YourSpecialException(ee.getMessage); 
    } 
    } 
no
Cuestiones relacionadas