【问题标题】:Parallel recursive memoization in ScalaScala中的并行递归记忆
【发布时间】:2013-01-07 21:15:14
【问题描述】:

我在 Scala 中有一个记忆的分而治之算法:

val cache = mutable.Map[Int, BigInt]()
cache(1) = BigInt(0)

def dp(n: Int): BigInt = cache.getOrElseUpdate(n, {
  partitions(n).map(i => dp(i)).min
  // partitions is non-recursive function that given an Int returns a list[Int]
})

然而,我想通过将partitions(n) 更改为partitions(n).par 来将此代码转换为使用并行化,而partitions(n).par 则返回一个并行列表。但是现在,我的cache 状态不佳,因为该映射不是并发的。当我用SynchronizedMap trait 实例化cache 时,我所有的fork 都会加入线程块,因为所有SynchronizedMap 所做的只是在getOrElseUpdate 方法调用周围放置一个巨大的synchronized 块。那么,使用记忆化并行执行递归分治算法的 Scala 习语是什么?

【问题讨论】:

    标签: scala recursion concurrency dynamic-programming memoization


    【解决方案1】:

    我的经验法则:永远不要创建自己的缓存。如果您真的想走可变路线,您可能需要查看GuavaCacheBuilder class。如果我没记错的话,它提供了适当的同步(和其他好处),但仍然非常轻量级。

    编辑:

    Scalaz 7 提供了一个Memo 类型,声称具有线程安全实现(immutableHashMapMemoimmutableListMapMemoimmutableTreeMapMemo)。乍一看,它看起来像你需要的,但我自己没有使用它,我有点怀疑:我认为用于存储相应地图的 var 应该标记为 @volatile 以避免可见性问题。

    【讨论】:

    • CacheBuilder 是我使用 Java 编码时会使用的第一件事。作为一个 Scala 迷,是否有任何 scala 友好的库或习语来解决这个问题?如果没有,我会尽快接受您的答复。谢谢!
    • 我只知道 Scalaz 中的 Memo 类型。我相应地编辑了我的答案。
    【解决方案2】:

    找到解决方案:val cache = concurrent.TrieMap[Int, BigInt] - concurrency != 同步

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 2012-09-27
      • 1970-01-01
      • 2018-09-08
      • 2012-11-26
      • 1970-01-01
      • 2015-05-03
      相关资源
      最近更新 更多