2012-10-28 5 views
9

のアクション私は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' 

私の推論は最初mapMresults'が含まれているリストに平行な戦略を適用し、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です。

+0

もっと見ることなく診断するのは難しいです。 '+ RTS -s -N'でそれを実行すると、変換された/枝刈りされた/飛び散ったスパークの統計情報は何ですか?そして 'f n'は実際に火花を発することができるサンクを返しますか? –

+0

@DanielFischerかなり長い(最小の例など)ので、私は完全なファイルを投稿することに少し躊躇しました。私は間違いが並列コードにあると思ったので、私はそれを私の質問に集中させました。私は今、新しい段落と '-s'統計(ひどいです)を追加しました。 – David

+0

実際にI/Oを実行しているものが破壊するかどうかは分かりませんが、純粋なものについては(Dataを使用していません。'parList'を呼び出しても、' parList'ではなく 'parListChunk k 'を使ってスピードアップ(およびより多く変換されたスパーク)を得ました。 –

答えて

7

戦略は、純粋な計算を並列実行するためのものです。 fIOの値を返すことが必須である場合は、代わりにasyncパッケージを使用することを検討してください。 IOのアクションを同時に実行するための便利なコンビネータを提供します。あなたのユースケースについては

mapConcurrently便利になります。

import Control.Concurrent.Async 

vals = [1..10] 
main = do 
    results <- mapConcurrently f vals 
    mapM_ print results 

(。私はあなたのfが正確であるかわからないので、私は、しかしテストしていません)

+0

テストしたい場合は、私のポストの最後にスクリプト。そうでない場合:Asyncは同じパフォーマンスヒットに悩まされますが、それは私がこれまで無視してきたことを非常に有望に思えるパッケージなので、ありがとうございます! – David

2

parallel-ioパッケージを試してみてください。 mapM_parallel_に変更することができます。

関連する問題