14

私は、Haskell演習でAndreLohの決定論的並列プログラミングの演習を行っていました。ストラテジーを使用してN-Queensシーケンシャルコードをパラレルに変換しようとしましたが、パラレルコードの実行がシーケンシャルコードよりもはるかに遅く、スタックスペースが不十分な場合にエラーが発生することに気付きました。

これは、並列N-Queensのコードです。

import Control.Monad
import System.Environment
import GHC.Conc
import Control.Parallel.Strategies
import Data.List
import Data.Function

type PartialSolution = [Int] -- per column, list the row the queen is in
type Solution = PartialSolution

type BoardSize = Int

chunk :: Int -> [a] -> [[a]]
chunk n [] = []
chunk n xs = case splitAt n xs of
         (ys, zs) -> ys : chunk n zs

-- Generate all solutions for a given board size.
queens :: BoardSize -> [Solution]
--queens n = iterate (concatMap (addQueen n)) [[]] !! n
queens n = iterate (\l -> concat (map (addQueen n) l `using` parListChunk (n `div`            numCapabilities) rdeepseq)) [[]] !! n


-- Given the size of the problem and a partial solution for the
-- first few columns, find all possible assignments for the next
-- column and extend the partial solution.
addQueen :: BoardSize -> PartialSolution -> [PartialSolution]
addQueen n s = [ x : s | x <- [1..n], safe x s 1 ]

-- Given a row number, a partial solution and an offset, check
-- that a queen placed at that row threatens no queen in the
-- partial solution.
safe :: Int -> PartialSolution -> Int -> Bool
safe x []    n = True
safe x (c:y) n = x /= c && x /= c + n && x /= c - n && safe x y (n + 1)

main = do
        [n] <- getArgs
        print $ length $ queens (read n)

この行(\l -> concat (map (addQueen n) l using parListChunk (n div numCapabilities) rdeepseq))は、元のコードから変更したものです。Simon Marlowのソリューションを見たことがありますが、コードの速度低下とエラーの理由を知りたいと思いました。

前もって感謝します。

4

1 に答える 1

4

あなたはあまりにも多くの仕事を引き起こしています。のparListChunkパラメータは、div n numCapabilitiesおそらく、あなたのシステムでは 7 です (2 コアで、n ~ 14 で実行しています)。リストは非常に急速に大きくなるので、そのような小さな単位の作業を開始しても意味がありません (そして、それを の値に結び付けることが理にかなっている理由がわかりませんn)。

係数 10 を追加すると (この場合はスパーク ユニットを 70 にします)、シングル スレッドよりも明らかにパフォーマンスが向上します。また、あなたが参照しているスタックの問題はありません。parListChunk値を変更して問題が解決した場合は、バグとして報告します。

800 ごとにチャンクすると、時間は 7.9 秒に対して 5.375 秒になります。800 を超えると、パフォーマンスが再び悪化し始めます、ymmv.

編集:

[tommd@mavlo Test]$ ghc --version
The Glorious Glasgow Haskell Compilation System, version 7.0.4
[tommd@mavlo Test]$ ghc -O2 so.hs -rtsopts -threaded -fforce-recomp ; time ./so 13 +RTS -N2
[1 of 1] Compiling Main             ( so.hs, so.o )
Linking so ...
73712
real    0m5.404s

[tommd@mavlo Test]$ ghc -O2 so.hs -rtsopts -fforce-recomp ; time ./so 13
[1 of 1] Compiling Main             ( so.hs, so.o )
Linking so ...
73712
real    0m8.134s
于 2012-04-05T09:21:31.450 に答える