并行排序IO操作

Dav*_*vid 11 io parallel-processing haskell

我有一个返回IO动作的函数,

f :: Int -> IO Int
Run Code Online (Sandbox Code Playgroud)

我想为参数的多个值并行计算这个函数.我天真的实施如下:

import Control.Parallel.Strategies

vals = [1..10]
main = do
      results <- mapM f vals
      let results' = results `using` parList rseq
      mapM_ print results'
Run Code Online (Sandbox Code Playgroud)

我给这理由是,第一mapM结合型的东西IO [Int]results,results'应用并行的策略所包含的名单,并mapM_通过打印,最后请求的实际值-但究竟是要打印并行已经引起的,所以程序应并行.

在确实使用了我所有的CPU之后感到高兴,我注意到程序在运行时效果较差(如挂钟时间),而+RTS -N8不是没有任何RTS标志.我能想到的唯一解释是,第一个mapM必须排序 - 即执行 - 所有IO操作已经,但这不会导致无效,但使N8执行与非平行的一样有效,因为所有的工作都由主线程.以+RTS -N8 -s收益率运行程序SPARKS: 36 (11 converted, 0 overflowed, 0 dud, 21 GC'd, 4 fizzled),这肯定不是最优的,但不幸的是我无法理解它.

我想我已经在Haskell并行化或IO monad的内部找到了初学者的垫脚石之一.我究竟做错了什么?

背景信息:f n是一个返回Project Euler问题n的解决方案的函数.由于其中许多都有要读取的数据,因此我将结果放入IO monad中.它看起来如何的一个例子是

-- 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
Run Code Online (Sandbox Code Playgroud)

完整的文件可以在这里找到(它有点长,但前几个"euler X"函数应该足够代表),我做并行性的主文件就是这个.

kos*_*kus 7

策略是并行执行纯计算.如果您确实要求f返回一个IO值,那么请考虑使用该async包.它为IO同时运行操作提供了有用的组合器.

对于您的用例,mapConcurrently看起来很有用:

import Control.Concurrent.Async

vals = [1..10]
main = do
  results <- mapConcurrently f vals
  mapM_ print results
Run Code Online (Sandbox Code Playgroud)

(我没有测试过,因为我不知道你f到底是什么.)