Haskell:尝试并行`atomicModifyIORef`实现

时间:2012-04-18 05:40:43

标签: haskell concurrency ioref

根据我的理解,对IORef的修改非常快,所有它们都涉及更新thunk指针。当然,读者(即想要在他们的网页上看到价值的人)将需要花时间来评估这些thunk(如果作者没有回读结果,这可能会积累。)

我认为开始实际评估IORef上的修改thunks是很好的,因为在许多情况下它们可能必须在某些时候进行评估(显然,这会打破无限的数据结构)。

所以我编写了以下函数,其签名与atomicModifyIORef类似:

atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
  let 
    g olddata = 
      let (newdata, result) = f olddata in (newdata, (result, newdata))
  in do
    (result, newdata) <- atomicModifyIORef ioref g
    force newdata `par` return result

这似乎有效(test code here)。我在这里做错了什么吗?或者有更好的方法吗?


编辑:第二次尝试

Carl's answer below的启发。我们实际上将force newdata存储到IORef中。这与newdata无关,但是显示了我们希望稍后保留force newdata的运行时,因此它不会垃圾收集火花。

atomicModifyIORefPar :: (NFData a) => IORef a -> (a -> (a, b)) -> IO b
atomicModifyIORefPar ioref f =
  let 
    g olddata = 
      let 
        (newdata, result) = f olddata
        newdata_forced = force newdata
      in 
        (newdata_forced, (result, newdata_forced))
  in do
    (result, newdata_forced) <- atomicModifyIORef ioref g
    newdata_forced `par` return result

1 个答案:

答案 0 :(得分:4)

根据GHC的版本,这可能有效,也可能无效。火花池与GC的相互作用在整个历史中都是可变的。在某些版本中,force newdata返回后范围内的任何内容都未引用表达式atomicModifyIORefPar这一事实意味着它可能在par创建的火花之前被垃圾收集。转换,这意味着火花也将被收集。

其他版本的GHC已将火花池视为GC分析的根源,但这也存在问题。我不记得当前状态是什么,但我怀疑它是火花池不算作GC的根源。它引发的问题(当返回的表达式不引用并行计算的表达式时失去并行性)比将Spark池视为GC根(保留不需要的内存)所产生的问题要小得多。 / p>


编辑 - 第二次尝试回答

由于您提供的原因,这个新的实施看起来是正确的。并行计算的表达式也可以从GC根源获得。