11

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]resultsresults'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" 関数は十分に代表的である必要があります)。私が並列処理を行うメイン ファイルはこれです。

4

2 に答える 2

7

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

あなたのユースケースでは、mapConcurrently役に立ちます:

import Control.Concurrent.Async

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

(ただし、あなたが正確に何であるかがわからないため、テストしていませんf。)

于 2012-10-28T17:58:50.573 に答える
3

parallel-ioパッケージをお試しください。mapM_anyをに変更できますparallel_

于 2012-10-29T17:53:35.533 に答える