stu*_*ith 4 multithreading haskell ioref
我有一个长时间运行的过程forkIO'd,它产生像素颜色值:
takesAgesToRun :: [[Color]]
myForkedProcess :: IORef [[Color]] -> IO ()
myForkedProcess ref = do let colors = takesAgesToRun
writeIORef ref colors
Run Code Online (Sandbox Code Playgroud)
(其中Color只包含三个Double值).
正如预期的那样,当读取"另一侧"时IORef,存储的值只是一个thunk,因此会阻止主进程.
我知道我需要完全评估[[Color]]正常形式的值,但似乎有两种方法可以实现这一点,而且,我不确定如何将其合并到我的代码中.
我该怎么做?我是否使用rnf,deepSeq或其他一些线程策略?这些是其中一个首选,其他人是否已被弃用?它如何适合我的代码?
(PS请忽略这样一个事实,即将图像存储为颜色列表列表是愚蠢的 - 这只是代码的简化版本).
使用deepSeq.它就像使用一样seq.你会像这样合并它:
myForkedProcess :: IORef [[Color]] -> IO ()
myForkedProcess ref = do let colors = takesAgesToRun
deepSeq colors $ writeIORef ref colors
Run Code Online (Sandbox Code Playgroud)
这将强制在"writeIORef"调用之前完全评估"颜色".
为了使其工作,您将需要一个NFData实例Color.究竟如何写这取决于Color的定义,但这里有两个例子:
-- just for reference
data Color = Color Double Double Double
instance NFData Color where
rnf (Color r g b) = r `seq` g `seq` b `seq` ()
-- closer to the likely actual implementation for Color
data Color2 = Color2 !Double !Double !Double
instance NFData Color2 where
-- the default implementation is fine
Run Code Online (Sandbox Code Playgroud)
对于Color实例,您需要确保只要颜色是完全评估颜色的所有组件[1].那是他们seq的所作所为.我们可以使用seq而不是在deepSeq这里,因为我们知道每个组件都是a Double,因此由seq完全评估.如果组件是更复杂的数据类型,那么我们需要deepSeq在编写NFData实例时使用.
在Color2它的简单一点.由于爆炸模式,我们知道组件在何时被完全评估Color2.这意味着我们可以使用默认实现,该实现评估Color2为弱头正常形式,由于完全评估了爆炸模式.
rnf与Control.Parallel.Strategies结合使用时主要有用.这是目前的定义deepSeq
deepseq :: NFData a => a -> b -> b
deepseq a b = rnf a `seq` b
Run Code Online (Sandbox Code Playgroud)
所有deepseq都会调用rnf并保证对其output()进行求值.这是rnf直接使用的唯一方法.
[1] Haskell只提供两种评估内容的通用方法:模式匹配和seq.其他一切都建立在其中一个或两个上.对于NFData Color实例,Color首先通过与Color构造函数的模式匹配来评估WHNF ,然后通过seq评估组件.
当然还有第三种高度专业化的评估方法:即main :: IO ()执行一个函数 来评估().