Haskell 具有 Bang 模式的严格 MVar

Haskell Strict MVar with Bang pattern

执行以下代码示例大约需要 2 秒。但是,当删除第 14 行中的 bang 模式时,需要 60 秒。谁能解释一下这是怎么回事?

我使用的是严格的 MVar,因此无论放入 MVar 中什么,都应该完全评估为正常形式。在插入 MVar 之前,我不希望 Bang 模式产生任何明显的效果。

{-# LANGUAGE BangPatterns #-}

import           Control.Concurrent.MVar.Strict
import qualified Data.Text as T
import           Data.Text.Encoding

main :: IO ()
main = do
    mvar <- newMVar T.empty

    let bsArr = map (\i -> encodeUtf8 $ T.pack $ "some strange string " ++ show i) [0 .. 30000 :: Int]
        mvarWriter =
            \lbs ->
                let !decoded = decodeUtf8 lbs
                in  modifyMVar_ mvar (\oldText -> return $ oldText <> decoded)

    mapM_ (\lbs -> mvarWriter lbs) bsArr
    print . T.length =<< readMVar mvar

您的代码大致相当于:

  let !decoded = decodeUtf8 lbs
  oldText <- takeMVar mvar
  let !newText = oldText <> decoded
  putMVar mvar newText

没有刘海图案是这样的:

  oldText <- takeMVar mvar
  let !newText = oldText <> decodeUtf8 lbs
  putMVar mvar newText

没有 bang 模式,计算发生在可能的最新点。那是在插入新值之前。然而,此时 MVar 是空的:oldText 已经被取出。在此期间,没有其他线程可以计算任何东西。所以这意味着在任何给定时间只有一个线程可以进行实际计算。

bang 模式强制 decodeUtf8 lbsMVar 被采用之前进行评估。因此,这部分计算可以与其他线程并行进行。只有相对便宜的 oldText <> decoded 计算需要发生在临界区。