一个地图/折叠管道,其中每个"转换层"在Haskell中并行运行?("垂直"平行,而不是"水平"parMap.)

imz*_*hev 5 parallel-processing haskell pipeline stream fold

我所看到的关于并行列表处理的大多数问题都涉及通过分块列表并将每个块彼此并行处理而实现的并行性.

我的问题不同.

关于maps和folds 的序列,我有一些更简单/更愚蠢的想法:如果我们想简单地为第一个工作设置一个map应该与第二个并行完成的工作map怎么办?

我正在考虑的计算结构:

xs -- initial data

ys = y1 : y2 : ... : yn -- y1 = f x1, ... and so on.
-- computed in one parallel job.

zs = z1 : z2 : ... : zn -- z1 = g y1, ... and so on.
-- computed in another job (the applications of `g`), i.e., the "main" job.
Run Code Online (Sandbox Code Playgroud)

以下代码的精神会有效吗?

ys = map f xs
zs = ys `par` map g' ys
    where g' y = y `pseq` g y
Run Code Online (Sandbox Code Playgroud)

我只需要说,ys应该用一种deepSeq而不是简单的写作来评估 :

ys `par` ...
Run Code Online (Sandbox Code Playgroud)

因此,虽然主要工作是忙于计算a g,但我们也在同时强制过早计算ys.

这种方法有什么问题吗?

该文档和例子parpseq有点稀缺,我明白这将如何工作了.我的代码与我在一些示例中看到的不同之处在于,代码左侧的值parpseq我的代码中的值不同.

讨论

我能想到类似并行的其他类型转换(的fold,scan和更复杂的成分).

首先,我担心ys如果g太快,可以对元素进行两次评估......

这应该给出两个核心固定的两倍加速.

如果N在我的管道中有更多如此昂贵的转换节点(比方说),我会获得固定N时间的加速.

至于我的垂直并行VS他们(1,2,等)的水平(与实现parMap):我想获得更快的数据流.换句话说:我希望inits zs首先更快地看到中间结果(增量).

更正

好像我不明白pseq.考虑我上面的旧代码:

zs = ys `par` map g' ys
    where g' y = y `pseq` g y
Run Code Online (Sandbox Code Playgroud)

并重新读取文档pseq:

seq 它的参数都是严格的,因此编译器可以重新排列

a `seq` b
Run Code Online (Sandbox Code Playgroud)

进入....... ...注释并行代码时可能会出现问题,因为我们需要更多地控制评估顺序; 我们a之前可能想要评估b,因为我们知道b已经与之并行引发了par.

因此,在我的情况下,y是我想要引发和强迫的价值的一部分par所以它就像b,并且没有必要/感觉把它放在一个pseq,对吧?

但是,如果我们在地图上太快,我还是有点害怕它的计算是否会被意外重复......

我还看了一下Haskell中的并行和并发编程的第2章,但是他们谈论rparrseq......而且他们似乎暗示可以做rpar/rparrpar/rseq/rseq不用担心等待案件的价值的rpar/rpar.我有什么不对吗?