13

我知道 Guava 有一个优秀的缓存库,但我正在寻找一些更 Scala/功能友好的东西,我可以在其中执行类似cache.getOrElse(query, { /* expensive operation */}). 我还查看了Scalaz 的备忘录,但没有 lru 到期。

4

3 回答 3

17

Spray 人有一个使用 Futures的喷雾缓存模块。有一个普通的 LRU 版本和一个允许您指定明确的生存时间的版本,之后条目会自动过期。

Futures 的使用显然允许您编写不会阻塞的代码。不过,真正酷的是它解决了“雷声大雨点”问题作为奖励。比如说,对于不在缓存中的同一个条目,一堆请求同时进入。在一个简单的缓存实现中,一百个线程可能会错过缓存中的那个条目,然后跑去为那个缓存条目生成相同的数据,但当然其中 99% 只是浪费精力。你真正想要的是只有一个线程去生成数据,所有 100 个请求者都可以看到结果。如果您的缓存包含 Future,这很自然会发生:第一个请求者立即在缓存中安装 Future,因此只有第一个请求者未命中。所有 100 个请求者都会为生成的结果获得该 Future。

于 2013-01-30T15:42:40.160 回答
10

在Twitter 的 Scala Util 库中找到了我正在寻找的东西

于 2013-01-28T21:38:10.333 回答
3

基于 Java LinkedHashMap 并公开为 Scala mutable.Map 的 LRUCache 解决方案

import java.util.Collections.synchronizedMap

import scala.collection.JavaConversions._
import scala.collection.mutable

class LRUCache[K, V](maxEntries: Int)
  extends java.util.LinkedHashMap[K, V](100, .75f, true) {

  override def removeEldestEntry(eldest: java.util.Map.Entry[K, V]): Boolean 
     = size > maxEntries

}

object LRUCache {
  def apply[K, V](maxEntries: Int): mutable.Map[K, V] 
    = synchronizedMap(new LRUCache[K, V](maxEntries))
}

当 map size > maxEntries 最后最近使用的条目将被删除。

对于 LRU 策略,LinkedHashMap 第三个构造函数参数应该设置为 true。 LinkedHashMap(int initialCapacity, float loadFactor, boolean accessOrder)

使用示例:

val cache = LRUCache[String, Int](1000)
val key = "key1"
val value = 111

cache.get(key) shouldBe None
cache += key -> value
cache.get(key) shouldBe Some(value)
cache(key) shouldBe value
于 2019-11-30T13:28:35.620 回答