从Haskell向量包安全并行使用MVector/IOVector

Nei*_*own 8 haskell

我可以安全地从多个并行线程分配IOVector的非重叠索引(来自Haskell向量包),还是需要额外的互斥锁?

背景:我想并行运行IO计算的集合,然后记录所有结果.我开始将结果返回到列表中,但这似乎是错误的数据结构.所以我希望使用vector包中的IOVector来存储结果.

我的问题是,我可以这样写:

runPar :: [IO a] -> IO (IOVector a)
runPar tasks = do
  v <- new (length tasks)
  mapM forkIO [task >>= write v i | (i, task) <- zip [0..] tasks]
  -- Wait for all tasks to complete
  return v
Run Code Online (Sandbox Code Playgroud)

这保证是安全的吗?或者我是否需要具有类似互斥锁的控件(例如,将v保持在一个中MVar)以确保一次只进行一次写操作?

Joa*_*ner 2

从代码和评论中的讨论来看,似乎没有理由假设它不是线程安全的。为了支持这一点,这里有一个小测试:

import qualified Data.Vector.Mutable as V
import System.Environment
import Control.Concurrent.Async

thread v i 0 = return ()
thread v i n = do
    x <- V.read v i
    V.write v i $! x-1
    thread v i (n-1)

main = do
    [m,n] <- map read `fmap` getArgs
    v <- V.replicate m n
    tis <- mapM (\i -> async (thread v i n)) [0..m-1]
    mapM_ wait tis
    r <- mapM (V.read v) [0..m-1]
    if all (== 0) r then putStrLn "OK" else putStrLn $ "Not OK: " ++ show r
Run Code Online (Sandbox Code Playgroud)

在这里,即使并行产生 100 个线程,从 1000000 开始倒数,使用-RTS -N​​ or -RTS -N10,总是会产生OK。