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
何かをバインドし、含まれているリストに並列戦略を適用し、最後に実際の値を出力して要求することでした-しかし、出力されるものはすでに並列にスパークしているので、プログラムは並列化します。IO [Int]
results
results'
mapM_
+RTS -N8
実際にすべての CPU を使用していることに満足した後、RTS フラグなしで実行した場合よりも実行した場合の方がプログラムの効果が低いことに気付きました (ウォール クロック時間のように) 。私が考えることができる唯一の説明は、最初mapM
にすべての IO アクションをシーケンスする (つまり実行する) 必要があるということN8
です。マスタースレッド。確かに+RTS -N8 -s
最適SPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled)
ではありませんが、残念ながら私はそれを理解することはできません。
Haskell の並列化または IO モナドの内部で、初心者の足がかりの 1 つを見つけたと思います。私は何を間違っていますか?
背景情報:f n
プロジェクト オイラーの問題 n の解を返す関数です。それらの多くは読み取るデータを持っているので、結果を IO モナドに入れます。それがどのように見えるかの例は次のとおりです
-- 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
完全なファイルはここにあります(少し長いですが、最初のいくつかの "euler X" 関数は十分に代表的である必要があります)。私が並列処理を行うメイン ファイルはこれです。