Как кэшировать результаты в scala?
Эта страница содержит описание метода использования карты getOrElseUpdate
:
object WithCache{
val cacheFun1 = collection.mutable.Map[Int, Int]()
def fun1(i:Int) = i*i
def catchedFun1(i:Int) = cacheFun1.getOrElseUpdate(i, fun1(i))
}
Итак, вы можете использовать catchedFun1
, который будет проверять, содержит ли cacheFun1
ключ и возвращаемое значение, связанные с ним. В противном случае он вызовет fun1
, затем кеш fun1
приведет к cacheFun1
, а затем вернет результат fun1
.
Я вижу одну потенциальную опасность - cacheFun1
может стать большим. Так что cacheFun1
нужно как-то очистить сборщик мусора?
P.S. Что насчет scala.collection.mutable.WeakHashMap and java.lang.ref.*
?
Ответы
Ответ 1
См. шаблон памятки и реализация Scalaz указанной статьи.
Также проверьте реализацию STM, например Akka.
Не то, чтобы это было только локальное кэширование, поэтому вы можете посмотреть в распределенный кеш или STM, например CCSTM, Terracotta или Hazelcast
Ответ 2
Взгляните на кеширование спрей (супер простое использование)
http://spray.io/documentation/1.1-SNAPSHOT/spray-caching/
упрощает работу и имеет приятные функции
например:
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")
}
}
Ответ 3
В списке рассылки scala они иногда указывают на MapMaker в библиотеке коллекций Google. Вы можете посмотреть на это.
Ответ 4
Поскольку ранее не упоминалось, позвольте мне поставить на стол свет Spray-Caching, который можно использовать независимо от Spray и обеспечивает ожидаемый размер, время жизни, время-в-время для выселения стратегий.
Ответ 5
Для простых запросов кэширования я все еще использую Guava cache solution в Scala.
Легкий и боевой тест.
Если это соответствует вашим требованиям и ограничениям, описанным ниже, это может быть отличным вариантом:
- Желание потратить некоторую память для повышения скорости.
- Ожидая, что ключи будут иногда запрашиваться более одного раза.
- В вашем кеше не нужно хранить больше данных, чем то, что поместилось бы в ОЗУ. (Ключи Guava являются локальными для одного запуска вашего приложения.
Они не хранят данные в файлах или на внешних серверах.)
Пример для использования будет выглядеть примерно так:
lazy val cachedData = CacheBuilder.newBuilder()
.expireAfterWrite(60, TimeUnit.MINUTES)
.maximumSize(10)
.build(
new CacheLoader[Key, Data] {
def load(key: Key): Data = {
veryExpansiveDataCreation(key)
}
}
)
Чтобы прочитать это, вы можете использовать что-то вроде:
def cachedData(ketToData: Key): Data = {
try {
return cachedData.get(ketToData)
} catch {
case ee: Exception => throw new YourSpecialException(ee.getMessage);
}
}