[英]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.