簡體   English   中英

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

[英]Do not cache `lazy val`. Possible?

ObjectToBeCached類上,我們有一個lazy val以避免對數據庫的多次請求。 緩存相同的case class ,它還在lazy val上緩存對象(播放框架,memcache)。 問題是該對象很大,並且消耗了一些內存。

有沒有什么辦法可以解決lazy val本身的緩存問題,或者有一種替代解決方案可以為我們提供lazy val優勢,而無需緩存主要case class的大子對象?

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

感謝您的提示!

更新資料

有時候,我最初發布此問題時並沒有使用正確的術語。 這樣就絆腳了,要面對類似的挑戰。

我正在尋找一種避免對ObjectToBeCached類的惰性val進行序列化的方法,因為該惰性val將消耗過多的緩存內存。

因此,標題應該是如何避免惰性val的序列化的?

當然,如果不緩存對象,也不需要從數據庫中獲取蛋糕,就不能吃蛋糕。 如果您確定有磁盤空間,並且可以比數據庫檢索快很多,則可以自己(在磁盤等上)創建內存不足的緩存。 (但是,建立數據庫非常擅長於這種事情。)

如果對象是臨時的,則嘗試將其放入計算中:

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 ,如果創建對象后立即嘗試使多個線程立即使用該對象,則更多。)

如果您只是想不想對惰性val進行序列化(您最初並沒有在問題中要求!),這就是@transient注釋的用途。

如果您從查詢中長期需要的內存遠小於結果集本身,則可以使用以下模式:

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

現在,查詢將按需執行,原始查詢結果將被垃圾回收,僅保留派生的信息。

我認為您有興趣創造隨需應變的價值,但並不能永遠保持下去。 在這種情況下, lazy val更改為def

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM