如果我在
Hoogle上搜索
IORef a -> (a -> (a, b)) -> IO b
,第一个结果是
atomicModifyIORef :: IORef a -> (a -> (a, b)) -> IO b
基础Data.IORef
原子地修改
的内容。IORef
此函数对于在多线程程序中安全地使用
非常有用。如果您只有一个IORef
,那么使用IORef
访问和修改它将防止竞争条件。atomicModifyIORef
将原子性扩展到多个
是有问题的,因此建议如果您需要做更复杂的事情,那么使用IORefs
是一个好主意。MVar
不严格应用该功能。即使您所做的只是替换该值,了解这一点也很重要。例如,这会泄漏内存:atomicModifyIORef
ref <- newIORef '1' forever $ atomicModifyIORef ref (\_ -> ('2', ()))
使用
或
atomicModifyIORef'
可以避免此问题。atomicWriteIORef
该函数施加了内存屏障,防止重新排序;有关详细信息,请参阅 Data.IORef#memmodel。
(我不确定为什么,如果我单击这三个链接中的任何一个,生成的文档页面似乎不包含文本将泄漏内存,该文本包含在上面的摘录中。)
问题有两个方面:
atomicModifyIORef'
代替atomicModifyIORef
就不会泄漏?让我们运行代码。
ref <- newIORef '1'
在这行之后,IORef 的内容就是
'1'
。
让我们应用一次此操作:
atomicModifyIORef ref (\_ -> ('2', ()))
此行之后,IORef 的内容为
(\_ -> '2') '1'
。
请注意,由于懒惰,这not简化为'2'
。但被保留为未评估的重击。 (atomicModifyIORef'
会简化这一点)。
再次应用此操作:
atomicModifyIORef ref (\_ -> ('2', ()))
现在 IORef 的内容是
(\_ -> '2') ((\_ -> '2') '1')
。
等等,看到图案了吗?当我们可以(并且应该)简化其内容时,我们构建了越来越大的未评估的重击,浪费了内存。