[英]Haskell: Attempt at parallel `atomicModifyIORef` implementation
根据我的理解,对IORef
的修改非常快,所有它们都涉及更新thunk指针。 当然,读者(即想要在他们的网页上看到价值的人)将需要花时间来评估这些thunk(如果作者没有回读结果,这可能会积累)。
我认为开始实际上并行地评估IORef
上的修改IORef
是好的,因为在许多情况下它们可能必须在某个时候进行评估(显然,这将打破无限的数据结构)。
所以我编写了以下函数,与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
这似乎工作( 测试代码在这里 )。 我在这里做错了什么吗? 或者有更好的方法吗?
编辑:第二次尝试
灵感来自Carl的答案如下 。 我们实际存储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
根据GHC的版本,这可能有效,也可能无效。 火花池与GC的相互作用在整个历史中都是可变的。 在某些版本中,在atomicModifyIORefPar
返回之后,范围内的任何东西都没有引用表达式force newdata
的事实意味着它可能会在par
之前创建的spark被转换之前被垃圾收集,这意味着火花也将被收集。
其他版本的GHC已将火花池视为GC分析的根源,但这也存在问题。 我不记得当前状态是什么,但我怀疑它是火花池不算作GC的根源。 它引发的问题(当返回的表达式不引用并行计算的表达式时失去并行性)比将Spark池视为GC根(保留不需要的内存)所产生的问题要糟糕得多。
编辑 - 第二次尝试回答
由于您给出的原因,这个新的实现看起来正确。 并行计算的表达式也可以从GC根源到达。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.