This page has a description of Map's getOrElseUpdate
usage method:
object WithCache{
val cacheFun1 = collection.mutable.Map[Int, Int]()
def fun1(i:Int) = i*i
def catchedFun1(i:Int) = cacheFun1.getOrElseUpdate(i, fun1(i))
}
So you can use catchedFun1
which will check if cacheFun1
contains key and return value associated with it. Otherwise, it will invoke fun1
, then cache fun1
's result in cacheFun1
, then return fun1
's result.
I can see one potential danger - cacheFun1
can became to large. So cacheFun1
must be cleaned somehow by garbage collector?
PS What about scala.collection.mutable.WeakHashMap and java.lang.ref.*
?
See the Memo pattern and the Scalaz implementation of said paper.
Also check out a STM implementation such as Akka .
Not that this is only local caching so you might want to lookinto a distributed cache or STM such as CCSTM , Terracotta or Hazelcast
Take a look at spray caching (super simple to use)
http://spray.io/documentation/1.1-SNAPSHOT/spray-caching/
makes the job easy and has some nice features
for example :
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")
}
}
On the scala mailing list they sometimes point to the MapMaker in the Google collections library . You might want to have a look at that.
For simple caching needs, I'm still using Guava cache solution in Scala as well. Lightweight and battle tested.
If it fit's your requirements and constraints generally outlined below, it could be a great option:
Example for using it will be something like this:
lazy val cachedData = CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.maximumSize(10)
.build(
new CacheLoader[Key, Data] {
def load(key: Key): Data = {
veryExpansiveDataCreation(key)
}
}
)
To read from it, you can use something like:
def cachedData(ketToData: Key): Data = {
try {
return cachedData.get(ketToData)
} catch {
case ee: Exception => throw new YourSpecialException(ee.getMessage);
}
}
由于之前没有提到过,让我把可以独立于 Spray 使用的轻量级Spray-Caching放在桌面上,并提供预期的大小、生存时间、空闲时间驱逐策略。
We are using Scaffeine (Scala + Caffeine), and you can read abouts its pros/cons compared to other frameworks over here .
You add your sbt,
"com.github.blemale" %% "scaffeine" % "4.0.1"
Build you cache
import com.github.blemale.scaffeine.{Cache, Scaffeine}
import scala.concurrent.duration._
val cachedItems: Cache[String, Int] =
Scaffeine()
.recordStats()
.expireAtferWrite(60.seconds)
.maximumSize(500)
.buid[String, Int]()
cachedItems.put("key", 1) // Add items
cache.getIfPresent("key") // Returns an option
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.