gpt4 book ai didi

scala - 如何在Scala中实现不可变缓存?

转载 作者:行者123 更新时间:2023-12-02 10:50:07 29 4
gpt4 key购买 nike

假设我有一个服务器,它根据客户端请求调用一个耗时的函数slow: Int => String。如果slow超时内没有返回,服务器将向客户端返回错误。

def trySlow(timeout: Duration)(id: Int): Try[String] = {
val fut = Future(slow(id))
try {
Await.ready(fut, timeout).value match {
case Some(r) => r
case None => Failure(new TimeoutException()) // should not happen
}
} catch {
case e: TimeoutException => Failure(e)
}
}

现在我想缓存 future,以便使用相同 id 调用 trySlow 的多个线程将等待相同的 future。

我将使用可变并发 TrieMap实现单例缓存。

case class CacheEntry (
future: Future[String],
start: Long = System.currentTimeMillis() // need it to clean the cache
)

type Cache = TrieMap[Int, CacheEntry]

def trySlow(timeout: Duration, cache: Cache)(id: Int): Try[String] = {

val fut = cache.getOrElseUpdate(id, CacheEntry(Future(slow(id))))

... // as in above
}

这有道理吗?如何使用不可变非单一缓存来做到这一点?

最佳答案

如果你只想使用 scala 集合中的内容,scala.collection.concurrent.TrieMap 是一个不错的选择。但是,请注意 TrieMap#getOrElseUpdate 有一个 thread safety bug这个问题最近才在 2.11.6 中修复。

如果您能承受额外的依赖,guava cache非常适合编写这样的缓存。特别是如果您希望缓存中的条目以某种方式过期。

关于缓存的 API:假设您正在谈论纯函数,缓存生成器应该只是一个接受函数 T => U 并返回函数 T => U 的东西

所以沿着这些思路:

object Cached {
def apply[T,U](f: T=>U): T=>U = { ??? }
}

用法:

def slow(id: Int): Try[String] = ??? // something complex including futures, timeouts etc.
val fast: Int => Try[String] = Cached(slow)

缓存 API 不必了解有关正在缓存的函数的任何信息,除非您希望它是纯粹的。

关于scala - 如何在Scala中实现不可变缓存?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30622896/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com