不要缓存`lazy val`。可能?

时间:2014-03-06 20:26:06

标签: scala caching playframework-2.0

在类ObjectToBeCached上,我们有一个lazy val,以避免对数据库的多个请求。同样缓存case class的{​​{1}}缓存(播放框架,内存缓存)lazy val上的对象。问题是对象相当大并且消耗了相当多的内存。

有没有什么方法可以绕过lazy val本身的缓存,或者在没有缓存主lazy val的大子对象的情况下为case class提供优势的替代解决方案?< / p>

case class ObjectToBeCached() {
   lazy val someAttribute:Option[BigObject] = retrieveBigObjectFromDatabase()
}

感谢任何提示!

更新

有时,我在最初发布此问题时没有使用正确的术语。因为这个问题磕磕绊绊,面对类似的挑战。

我一直在寻找一种方法来避免类ObjectToBeCached的lazy val的序列化,因为lazy val会消耗太多的缓存。

因此,标题应该是如何避免lazy val的序列化?

3 个答案:

答案 0 :(得分:2)

当然,如果没有缓存对象,又不需要从数据库中获取它,那么你就不能吃蛋糕了。如果您确定拥有磁盘空间并且这比数据库检索快得多,您可以自己创建内存不足的缓存(在磁盘或其他东西上)。 (但数据库的构建非常适合这种事情。)

如果对象是临时的,那么尝试将其置于计算中:

lazy val keepThisForever = {
  val cacheThisForRightNow = readFromDB()
  f(cacheThisForRightNow)
  ...
  answer
}

或者如果不可能,将其分配给var并在可能时手动清除它。

或者,如果你想要缓存的项目,但只有你有足够的内存来存储它,你可以使用软引用,它可以这样封装:

// Use this to cache expensive computations that are cleared when
// memory gets especially tight (via SoftReference); not thread-safe
class Soft[T,U](t: T)(gen: T => U) {
  private[this] var cache = new java.lang.ref.SoftReference(gen(t))
  def apply(): U = {
    var u = cache.get()
    if (u==null) {
      u = gen(t)
      cache = new java.lang.ref.SoftReference(u)
    }
    u
  }
}
object Soft {
  def apply[T,U](t: T)(gen: T => U) = new Soft(t)(gen)
}

现在你可以

val queryResult = Soft(queryString)(readFromDB)

并使用

进行访问
queryResult()

您可以在需要时从数据库中读取数据。

(如果您需要线程安全,则必须至少将调用同步到apply,如果您尝试让多个线程在创建后立即使用该对象,则必须更多。)

如果你的意思是你不希望lazy val序列化(你最初没有在你的问题中提出这个问题!),这就是@transient注释的用途。

答案 1 :(得分:1)

如果查询中长期需要的内容比结果集本身小得多,则可以使用这种模式:

lazy val queryResult = {
  val resultSet = doTheQuery(...)
  extractQueryInfo(resultSet)
}

现在查询将按需执行,原始查询结果将被垃圾收集,只保留派生信息。

答案 2 :(得分:0)

我认为您有兴趣按需创建价值,但不会永远保持价值。在这种情况下,请将lazy val更改为def