Tôi đang gặp sự cố để làm cho mã của mình chạy song song. Nó là trình tạo Delaunay 3D sử dụng thuật toán phân tách & có tên là DeWall.Song song về thuật toán phân chia và chinh phục
Các chức năng chính là:
deWall::[SimplexPointer] -> SetSimplexFace -> Box -> StateT DeWallSets IO ([Simplex], [Edge])
deWall p afl box = do
...
...
get >>= recursion box1 box2 p1 p2 sigma edges
...
...
Nó gọi là "đệ quy" chức năng mà có thể gọi hàm dewall lại. Và đây là nơi mà cơ hội parallization xuất hiện. Các mã sau đây cho thấy các giải pháp tuần tự.
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
Các đơn vị trạng thái và IO được sử dụng để dẫn đường trạng thái và tạo UID cho mỗi tứ diện được tìm thấy bằng MVar. Nỗ lực đầu tiên của tôi là thêm một ngã ba nhưng nó không hoạt động. Nó cung cấp cho một đầu ra sai do thiếu kiểm soát trong phần hợp nhất mà không chờ đợi cho cả hai chủ đề để kết thúc. Tôi không biết làm thế nào để làm cho nó chờ đợi cho họ.
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)
Vì vậy, nỗ lực tiếp theo của tôi là sử dụng chiến lược song song tốt hơn "par" và "pseq" cho kết quả phù hợp nhưng không thực hiện song song theo 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)
Tôi đang làm gì sai?
CẬP NHẬT: Bằng cách nào đó vấn đề này dường như có liên quan với sự hiện diện của các đơn vị IO. Trong một phiên bản cũ (cũ) không có đơn nguyên IO, chỉ có đơn vị Trạng thái, thực thi song song sẽ chạy với 'par'
và 'pseq'
. Các GHC -sstderr cho 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
Cloud có người giải thích điều đó?
Điều này giải quyết được vấn đề của tôi. Tôi đã thực hiện một sửa chữa nhỏ bằng cách sử dụng mv2 <- newEmptyMVar thay vì mv <- newMVar ([], []). Cảm ơn rất nhiều Axman6 – LambdaStaal