2010-09-06 1 views
21

This page ha una descrizione del metodo di getOrElseUpdate utilizzo di Map:Come memorizzare nella cache i risultati in 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)) 
} 

in modo da poter utilizzare catchedFun1 che controllerà se cacheFun1 contiene la chiave e il valore di ritorno ad esso associati. In caso contrario, invierà fun1, quindi memorizzerà il risultato di fun1 nella cacheFun1, quindi restituirà il risultato di fun1.

Posso vedere un potenziale pericolo - cacheFun1 può diventare troppo grande. Quindi cacheFun1 deve essere pulito in qualche modo dal garbage collector?

P.S. Che mi dici di scala.collection.mutable.WeakHashMap and java.lang.ref.*?

+3

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

risposta

6

Sulla mailing list scala sono sometimes in corrispondenza dello MapMaker nello Google collections library. Potresti volerlo dare un'occhiata.

+4

Google Collections è stato rinominato in Guava e il nuovo CacheBuilder è probabilmente una corrispondenza più stretta: http: //docs.guava-libraries.googlecode. com/git/javadoc/index.html? com/google/common/cache/CacheBuilder. html –

16

Vedere Memo pattern e Scalaz implementation di detta carta.

Controllare anche un'implementazione STM come Akka.

Non che questa è solo la cache locale in modo che si potrebbe desiderare di lookinto una cache distribuita o STM come CCSTM, Terracotta o Hazelcast

+1

Solo che il * Memo Pattern * utilizza 'WeahHashMap' e quindi non è una cache molto buona. – Debilski

+2

@Debilski Dipende dai requisiti della "cache". In questo caso una "cache debole" lavora per elevare le preoccupazioni dei posters che "cacheFun1 può [diventare troppo] grande" .. –

2

Dal momento che non è stato menzionato prima mi permetta di mettere sul tavolo la luce Spray-Caching che può essere utilizzato indipendentemente da Spray e fornisce le strategie di sfratto in base alle dimensioni, al tempo di vita e al minimo.

7

Date un'occhiata a spruzzo caching (super semplice da usare)

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

rende il lavoro facile ed ha alcune caratteristiche

ad esempio:

 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

Per semplice necessità di memorizzazione nella cache, sto ancora usando Guava cache solution in Scala. Leggero e testato.

Se adattarlo dei vostri requisiti e vincoli generalmente riportate qui di seguito, potrebbe essere una grande opzione:

  • Disposti a spendere un po 'di memoria per migliorare la velocità.
  • Prevedendo che a volte le chiavi vengano interrogate più volte.
  • La cache non avrà bisogno di memorizzare più dati di quelli che si adattano alla RAM. (Le cache di Guava sono locali per una singola esecuzione dell'applicazione Non memorizzano i dati nei file o su server esterni.)

Esempio per il suo utilizzo sarà qualcosa di simile:

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

di leggere da esso, è possibile usare qualcosa come:

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