据我了解,对IORef
s 的修改非常快,它们所涉及的只是更新一个 thunk 指针。当然,读者(即想要在他们的网页上看到价值的人)将需要花时间来评估这些 thunk(如果作者没有回读结果,这可能会增加)。
我认为最好开始IORef
并行地实际评估修改 thunk,因为在许多情况下,它们可能无论如何都必须在某个时候进行评估(显然,这将破坏无限的数据结构)。
因此,我编写了以下函数,其签名类似于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
这似乎有效(测试代码here)。我在这里做错了什么吗?还是有更好的方法来做到这一点?
编辑:第二次尝试
受以下卡尔回答的启发。我们实际上存储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