【发布时间】:2015-06-26 13:19:56
【问题描述】:
在关于 hackage 的 Control.Concurrent.MVar 文档中,我们有一个关于 MVars 使用的“陷阱”。这是link。
MVar 表示,当您使用putMVar 将某些内容放入MVar 中时,如果您放入的内容是一个巨大的thunk,则接收线程将执行混乱的评估工作,而不是发送线程。
除了可能令人讨厌或没有根据之外,为了纠正这种情况,它将我们指向evaluate 的方向,它本身说要使用seq。每个人都喜欢的 haskell 函数。
Evaluate 的语义应该是这样的:
evaluate x `seq` y ==> y
所以我的问题是:为什么不会在分叉线程中进行评估!?!?!
concTreeMap :: (a -> b) -> BinaryTree a -> IO (BinaryTree b)
concTreeMap f Leaf = return Leaf
concTreeMap f (Branch v l r) = do
res <- newEmptyMVar
forkIO $ do
let fv = f v
evaluate fv `seq` (putMVar res fv)
v' <- takeMVar res
l' <- concTreeMap f l
r' <- concTreeMap f r
return (Branch v' l' r')
已编辑以添加等效加速...
不知何故,这相当于下面的答案(不使用评估,而是使用 seq)......无论如何,我认为加速的重点在于 a)向 haskell 运行时提供关于 thunk 评估的提示和 2)移动带走的地方
concTreeMap :: (a -> b) -> BinaryTree a -> IO (BinaryTree b)
concTreeMap f Leaf = return Leaf
concTreeMap f (Branch v l r) = do
res <- newEmptyMVar
forkIO $ do { let fv = f v in fv `seq` putMVar res fv }
l' <- concTreeMap f l
r' <- concTreeMap f r
v' <- takeMVar res
return (Branch v' l' r')
【问题讨论】:
-
你引用的那个等式就是说
evaluate `seq` y和y是一样的,也就是说,你对evaluate的使用没有任何作用。