我可以安全地从多个并行线程分配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
这是否保证安全?或者我是否需要具有类似互斥锁的控件(例如,在MVar
中保持v)以确保一次只进行一次写入?
答案 0 :(得分: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
在这里,即使并行生成100个线程,从{100}开始倒计时,-RTS -N
或-RTS -N10
,也总是产生OK
。