【问题标题】:Functional value, mutable state and thread-safety函数值、可变状态和线程安全
【发布时间】:2014-06-05 23:46:59
【问题描述】:

From there

试图将memoization 引入递归算法。

case class Memo[A,B](f: A => B) extends (A => B) {
  private val cache = mutable.Map.empty[A, B]
  def apply(x: A) = cache getOrElseUpdate (x, f(x))
}

private val fib: Memo[Int, BigInt] = Memo {
  case 0 => 0
  case 1 => 1
  case n => fib(n-1) + fib(n-2) 
}

def foo(n: Int) = {
  fib(n)
} 

这是否意味着如果我们使用可变状态和函数值(由 val.. 几乎是函数值定义)那么它不是线程安全的?

val fib - 看起来像全局范围的可变变量/对象)

【问题讨论】:

  • 在这里,您可以使用 var 来挽救线程安全,该 var 持有不可变的 Map,每次更新都会替换该 @volatile。或者,您可以使用(有点)线程安全、可变的Map 类型TrieMap。请参阅 stackoverflow.com/questions/21286823/… 了解重要警告。
  • 实际上给定的多线程在构建 memoization 时并没有多大帮助:stackoverflow.com/a/20462893/2073130,仅在单线程中对 DP 使用 memoization。这样一来,普通的mutable.Map 就足够了。

标签: scala thread-safety dynamic-programming memoization


【解决方案1】:

我会说是的,如果更多线程同时调用foo 可能会出现问题。即使我在想,如果您只是添加到地图并且始终为键添加相同的值,也不能保证它一定可以工作。如果 Map 的 getOrElseUpdate 方法的实现无论出于何种原因都是有状态的,那么它将不起作用。可变 Map 的契约根据定义不是线程安全的。

如果可以的话,将同步添加到您的地图中就可以了:

private val cache = new HashMap[A, B] with SynchronizedMap[A, B]

【讨论】:

  • @DNA 在问题中只有Memo 的单个实例。如果您尝试提出另一种解决方案,那更好,但我试图回答他的问题。
  • 是的,我认为fibdef 而不是val,所以你说得对。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多