haskell - 并行排序 IO 操作

标签 haskell io parallel-processing

我有一个返回 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绑定(bind) 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是返回欧拉计划问题 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

完整文件可以在 here 找到(有点长,不过前面几个“euler X”函数应该足够有代表性),我做并行的主文件是this one .

最佳答案

策略用于并行执行纯计算。如果您的 f 确实必须返回 IO 值,那么请考虑使用 async 包。它提供了有用的组合器来同时运行 IO 操作。

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

import Control.Concurrent.Async

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

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

关于haskell - 并行排序 IO 操作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/13109946/

相关文章:

c++ - 通过延迟的 self 转换来 boost MSM并行行为?

haskell - 从 IO ExitCode monad 获取字符串

haskell - 为什么在没有括号的情况下不可能在haskell中乘以负数

haskell - 如何结合数据组合和 monad 转换器

java - 无法在Java中打印出集合

F#:告诉我我对使用 Async.Parallel 的遗漏

haskell - 结构化数据验证的依赖类型

java - Download 类是不可变性的糟糕候选者吗?

java - 多线程写入多个文件,但是会互相影响

CUDA:如何使该代码并行?