【发布时间】:2011-02-07 10:15:07
【问题描述】:
我在让我的代码并行运行时遇到了问题。它是一个 3D Delaunay 生成器,使用名为 DeWall 的分治算法。
主要功能是:
deWall::[SimplexPointer] -> SetSimplexFace -> Box -> StateT DeWallSets IO ([Simplex], [Edge])
deWall p afl box = do
...
...
get >>= recursion box1 box2 p1 p2 sigma edges
...
...
它调用可能回调 dewall 函数的“递归”函数。正是在这里出现了并行化机会。以下代码显示了顺序解决方案。
recursion::Box -> Box -> [SimplexPointer] -> [SimplexPointer] -> [Simplex] -> [Edge] -> DeWallSets -> StateT DeWallSets IO ([Simplex], [Edge])
recursion box1 box2 p1 p2 sigma edges deWallSet
| null afl1 && null afl2 = return (sigma, edges)
| (null) afl1 = do
(s, e) <- deWall p2 afl2 box2
return (s ++ sigma, e ++ edges)
| (null) afl2 = do
(s,e) <- deWall p1 afl1 box1
return (s ++ sigma, e ++ edges)
| otherwise = do
x <- get
liftIO $ do
(s1, e1) <- evalStateT (deWall p1 afl1 box1) x
(s2, e2) <- evalStateT (deWall p2 afl2 box2) x
return (s1 ++ s2 ++ sigma, e1 ++ e2 ++ edges)
where afl1 = aflBox1 deWallSet
afl2 = aflBox2 deWallSet
State 和 IO monad 用于传递状态并为使用 MVar 找到的每个四面体生成 UID。我的第一次尝试是添加一个 forkIO,但它不起作用。由于在不等待两个线程完成的合并部分期间缺乏控制,它给出了错误的输出。我不知道如何让它等待他们。
liftIO $ do
let
s1 = evalStateT (deWall p1 afl1 box1) x
s2 = evalStateT (deWall p2 afl2 box2) x
concatThread var (a1, b1) = takeMVar var >>= \(a2, b2) -> putMVar var (a1 ++ a2, b1 ++ b2)
mv <- newMVar ([],[])
forkIO (s1 >>= concatThread mv)
forkIO (s2 >>= concatThread mv)
takeMVar mv >>= \(s, e) -> return (s ++ sigma, e ++ edges)
所以,我的下一个尝试是使用更好的并行策略“par”和“pseq”,它给出了正确的结果,但根据 threadScope 没有并行执行。
liftIO $ do
let
s1 = evalStateT (deWall p1 afl1 box1) x
s2 = evalStateT (deWall p2 afl2 box2) x
conc = liftM2 (\(a1, b1) (a2, b2) -> (a1 ++ a2, b1 ++ b2))
(stotal, etotal) = s1 `par` (s2 `pseq` (s1 `conc` s2))
return (stotal ++ sigma, etotal ++ edges)
我做错了什么?
更新:不知何故,这个问题似乎与 IO monad 的存在有关。在没有 IO monad、只有 State monad 的另一个(旧)版本中,并行执行使用 'par' 和 'pseq' 运行。 GHC -sstderr 给出SPARKS: 1160 (69 converted, 1069 pruned)。
recursion::Box -> Box -> [SimplexPointer] -> [SimplexPointer] -> [Simplex] -> [Edge] -> DeWallSets -> State DeWallSets ([Simplex], [Edge])
recursion p1 p2 sigma deWallSet
| null afl1 && null afl2 = return sigma
| (null) afl1 = do
s <- deWall p2 afl2 box2
return (s ++ sigma)
| (null) afl2 = do
s <- deWall p1 afl1 box1
return (s ++ sigma)
| otherwise = do
x <- get
let s1 = evalState (deWall p1 afl1 box1) x
let s2 = evalState (deWall p2 afl2 box2) x
return $ s1 `par` (s2 `pseq` (s1 ++ s2 ++ sigma))
where afl1 = aflBox1 deWallSet
afl2 = aflBox2 deWallSet
云有人解释一下吗?
【问题讨论】:
标签: haskell concurrency functional-programming parallel-processing