如何在scala中缓存结果?

时间:2010-09-06 12:09:59

标签: scala caching

This page描述了地图的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.*呢?

6 个答案:

答案 0 :(得分:16)

请参阅所述论文的Memo patternScalaz implementation

同时查看STM实施,例如Akka

这不仅仅是本地缓存,因此您可能希望查看分布式缓存或STM,例如CCSTMTerracottaHazelcast

答案 1 :(得分:8)

看看喷雾缓存(超级简单易用)

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")
        }
      }

答案 2 :(得分:6)

在scala邮件列表中,他们sometimes指向MapMaker中的Google collections library。你可能想看一下。

答案 3 :(得分:3)

对于简单的缓存需求,我仍然在Scala中使用Guava cache solution。 轻量级和战斗测试。

如果符合您的要求和约束条件,则可能是一个很好的选择:

  • 愿意花一些记忆来提高速度。
  • 期望有时会多次查询密钥。
  • 您的缓存不需要存储比RAM中更多的数据。 (番石榴缓存是您运行一次的本地缓存。 它们不会将数据存储在文件中或外部服务器上。)

使用它的示例如下:

  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);
    }
  }

答案 4 :(得分:2)

由于之前没有提到过,让我在桌面上摆放可以独立于Spray使用的灯Spray-Caching,并提供预期的尺寸,生存时间,空闲时间驱逐策略。

答案 5 :(得分:1)

我们正在使用 Scaffeine (Scala + Caffeine),您可以通过 here 了解其与其他框架相比的优缺点。

你添加你的 sbt,

"com.github.blemale" %% "scaffeine" % "4.0.1"

建立你的缓存

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