【问题标题】:Using Haskell's MVar package but enforcing strictness with seq使用 Haskell 的 MVar 包,但使用 seq 执行严格性
【发布时间】: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` yy是一样的,也就是说,你对evaluate的使用没有任何作用。

标签: multithreading haskell


【解决方案1】:

假设您按照 Petr Pudlá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')

?

【讨论】:

  • 你是一个活着的传奇。现在我怎么把积分兑现给你们两个哈哈?!?!?
【解决方案2】:

因为您使用seq 来强制评估evaluate fv。这是一个IO 操作,评估它与运行它完全不同。

如果您将 IO 操作视为配方,则在其上运行 seq 并对其进行评估,只是确保配方已完全写下,但运行实际上是在使用配方来产生一些东西。

应该改为分叉部分

forkIO $ do
          let fv = f v
          evaluate fv
          putMVar res fv

【讨论】:

  • 我明白你在说什么,但这仍然比不同时执行要慢。我也觉得你可能没有足够的信息来诊断这个问题,虽然......嗯
  • @lol 你如何测量速度?你的f 有多复杂?您确定并发过度(切换 CPU 上下文,使用MVars 不大于并行化的收益吗?
  • f 是一个阶乘函数,我用time 对其进行计时,对于曾经在这里实现它的谷歌用户,记得使用ghc -threaded 编译,控制O1,@987654334 @等在你的测试中
  • @lol 听起来不错。 criterion 提供比time 更准确的测量。
猜你喜欢
  • 2014-02-12
  • 2014-12-14
  • 2012-06-18
  • 1970-01-01
  • 2015-08-06
  • 2012-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多