【发布时间】:2021-10-11 07:39:11
【问题描述】:
我在 ST monad 中有这个可变数组。我有这个循环功能。
runST $ do
myarray <- newMArray (Sz 10) 0
loopM_ 0 (<10) (+1) (\j ->
loopM_ 0 (<10) (+1) (\i ->
when (mytruthcheck j i)
(modifyM_ myarray (pure . (+1)) ((funcofji j i) :: Int)
)))
我想使用forkST_ 像这样并行运行外循环。
runST $ do
myarray <- newMArray (Sz 10) 0
loopM_ 0 (<10) (+1) (\j ->
void (forkST_ (loopM_ 0 (<10) (+1) (\i ->
when (mytruthcheck j i)
(Data.Massiv.Array.Mutable.modifyM_
myarray (pure . (+1)) ((funcofji j i) :: Int)
))))
但我猜这会导致线程冲突,但我真的不知道,虽然我知道funcofji 可以为j 的不同值输出相同的值,因此循环可以修改myarray 的相同索引用于不同的 j s。有没有办法确保这是以原子方式完成的,还是已经如此?
顺便说一句,这是loopM_ 函数
loopM_ :: Monad m => Int -> (Int -> Bool) -> (Int -> Int) -> (Int -> m a) -> m ()
loopM_ !init' condition increment f = go init'
where
go !step
| condition step = f step >> go (increment step)
| otherwise = pure ()
【问题讨论】:
-
很确定如果您要强制执行原子性,那么缓存惩罚将破坏任何多线程优势。只有在每个数组元素上计算一个非常昂贵的函数时,它才能得到回报。
-
如果数组大小不是太大,那么你可以用不同的数组计算并行部分,然后将它们合并在一起(有一个幺半群)。
-
如果你想要并行化(不是并发),那么
forkST/forkIO产生的 Haskell 线程的数量应该与你机器上的 CPUs/Cores 的数量有关。否则将是开销。 -
@Anon 没有。
forkST没有问题,你打电话给forkST的数量有问题。forkOn帮不了你。你应该在一些计数上分割你的迭代范围(可以等于你机器上 CPU 的计数),然后在子范围上分叉循环。 -
实现的另一个问题是您没有等待所有并行工作完成。
标签: haskell concurrency parallel-processing massiv