使用Haskell的MVar包但强制执行seq的严格性

lol*_*lol 2 multithreading haskell

Control.Concurrent.MVar关于hackage 的文档中,我们对MVars 的使用有一个'问题' .这是链接.

MVar说,当你使用putMVar某个东西放入时MVar,如果你放入的东西是一个巨大的东西,接收线程将有凌乱的评估工作,而不是发送线程.

除了可能令人讨厌或无根据之外,为了弥补这种情况,它指出了我们evaluate自己所说的使用方向seq.每个人最喜欢的haskell功能.

评估的语义应该是这样的:

evaluate x `seq` y    ==>  y
Run Code Online (Sandbox Code Playgroud)

所以我的问题是:为什么不在分叉线程中进行评估!?!?!

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')
Run Code Online (Sandbox Code Playgroud)

编辑添加等效的加速...

不知何故,这相当于下面的答案(不使用评估,但使用seq)...无论如何,我认为加速的重点在于a)提供关于thunk评估的haskell运行时的提示和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')
Run Code Online (Sandbox Code Playgroud)

Rei*_*ton 6

假设你按照PetrPudlák的回答修改你的程序,你试图MVar在启动线程后立即从中获取一个值.所以你没有并行性,因为线程运行concTreeMap必须等待MVar它被填满,这意味着等待分叉线程放入fv,MVar直到它评估它之后它才会执行.与此同时,原始线程无所作为.

你不是故意写的吗?

  ...
  forkIO $ do
              let fv = f v
              evaluate fv `seq` (putMVar res fv)
  l' <- concTreeMap f l
  r' <- concTreeMap f r
  v' <- takeMVar res         -- Note: this moved to after we do more work
  return (Branch v' l' r')
Run Code Online (Sandbox Code Playgroud)


Pet*_*lák 5

因为你seq以前强迫评价evaluate fv.这是一个IO动作,并且评估它与运行它完全不同.

如果您将一个IO动作视为一个配方,seq在它上面运行,评估它,只是确保配方完全写下来,但是运行实际上是使用配方来生成一些东西.

分叉部分应该是

forkIO $ do
          let fv = f v
          evaluate fv
          putMVar res fv
Run Code Online (Sandbox Code Playgroud)