のアクション私はIOアクションを返す関数を持って、シーケンシングIO平行
f :: Int -> IO Int
私は、引数の複数の値のために並列に、この関数を計算したいと思います。次のように私の素朴な実装されました:このため
import Control.Parallel.Strategies
vals = [1..10]
main = do
results <- mapM f vals
let results' = results `using` parList rseq
mapM_ print results'
私の推論は最初mapM
がresults'
が含まれているリストに平行な戦略を適用し、mapM_
が最終的にすることにより、実際の値を要求し、results
にタイプIO [Int]
の何かを結合することでしたそれらを印刷する - しかし、何が印刷されるのかは既に並列で発生しているので、プログラムを並列化する必要があります。
本当にすべてのCPUを使用していることを嬉しく思ってから、+RTS -N8
で実行されているときは、プログラムはRTSフラグなしでは効果が薄いことに気付きました。私が考えることができる唯一の説明は、最初のmapM
はすべてのIOアクションを既にシーケンスしている、つまり実行していますが、無効ではありませんが、すべての作業が完了しているので、N8
をマスタースレッドによって行われます。 +RTS -N8 -s
でプログラムを実行すると、必ずしも最適ではないSPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled)
が得られますが、残念ながら私はそれを理解できません。
ハスケルの並列化またはIOモナドの内部で、初心者の踏み台の1つを見つけたとします。私は間違って何をしていますか?
背景情報:f n
は、Project Euler問題nの解を返す関数です。多くの人が読み込むデータを持っているので、結果をIOモナドに入れます。それはのように見えるかもしれ方法の例は、完全なファイルがhere(それは少し長いですが、最初のいくつかの「オイラーX」の機能が十分に代表するものでなければならない)、私はメインのファイルを見つけることができます
-- Problem 13: Work out the first ten digits of the sum of one-hundred 50-digit numbers.
euler 13 = fmap (first10 . sum) numbers
where
numbers = fmap (map read . explode '\n') $ readFile "problem_13"
first10 n
| n < 10^10 = n -- 10^10 is the first number with 11 digits
| otherwise = first10 $ n `div` 10
です並列性はthis oneです。
もっと見ることなく診断するのは難しいです。 '+ RTS -s -N'でそれを実行すると、変換された/枝刈りされた/飛び散ったスパークの統計情報は何ですか?そして 'f n'は実際に火花を発することができるサンクを返しますか? –
@DanielFischerかなり長い(最小の例など)ので、私は完全なファイルを投稿することに少し躊躇しました。私は間違いが並列コードにあると思ったので、私はそれを私の質問に集中させました。私は今、新しい段落と '-s'統計(ひどいです)を追加しました。 – David
実際にI/Oを実行しているものが破壊するかどうかは分かりませんが、純粋なものについては(Dataを使用していません。'parList'を呼び出しても、' parList'ではなく 'parListChunk k 'を使ってスピードアップ(およびより多く変換されたスパーク)を得ました。 –