1

我正在使用该方法来缓存使用 http 调用的函数的结果。我的代码看起来像这样,并且 http 可能已经很糟糕了。

  def myData: Iterable[String] = {
    Cache.getOrElse[Iterable[String]](cacheKey, cacheExpiration)(Await.result(myHttpCallFunction(), Duration.apply(500, TimeUnit.MILLISECONDS)))
  }

我曾经把它当作

  val myData: Iterable[String] = Await.result(myHttpCallFunction(), Duration.apply(500, TimeUnit.MILLISECONDS))

我的代码线程现在安全吗?或者我应该做点别的。我必须说我对 scala 很陌生,而且我对它的内部工作不是很熟悉。如果它不是线程安全的:我怎样才能做到这一点?

4

1 回答 1

4

根据源代码,无论缓存实现如何 ,它都不是线程安全的。

def getOrElse[A](key: String, expiration: Int = 0)(orElse: => A)(implicit app: Application, m: ClassManifest[A]): A = {
    getAs[A](key).getOrElse {
      val value = orElse
      set(key, value, expiration)
      value
    }
  }

想想这个场景:

  1. 第一个请求以 100 毫秒的时间戳进入
  2. 缓存中不存在key,所以执行orElse初始化缓存值,假设需要50ms才能完成
  3. 第二个请求在时间戳 120ms 处为相同的键
  4. 因为第一个orElse还没有完成,缓存中没有找到值,所以再次执行orElse初始化缓存值
  5. 在时间戳 150 毫秒时,首先返回orElse并保存到地图
  6. 在时间戳 160 毫秒,第三个请求进入相同的密钥。缓存值将立即返回
  7. 在时间戳 170 毫秒时,第二个orElse返回。即使值已经缓存,缓存将被覆盖

因此,play Cache 插件非常适合提供可能需要很长时间才能初始化的静态数据。在这种情况下,通常多重初始化不是问题。

不要使用缓存来维护全局变量。

于 2013-05-31T18:48:55.620 回答