【发布时间】:2018-03-27 23:35:36
【问题描述】:
问题
我们认为并行处理每个“尾排列”会减少该算法的实际运行时间。为什么不呢?如果我们可以配置 PSeq 以提高运行时间,该怎么办?
let rec permute (xs:'t list) =
if xs.Length = 1 then [xs]
else ([], permute xs.Tail)
// Why do we not get a performance
// improvement when we use PSeq here
// relative to using Seq?
||> PSeq.fold (fun acc ps ->
(insertAtEach xs.Head ps)@acc)
permute ["A";"B";"C"] |> ignore
我们认为排列工作将按如下方式拆分,并且算法的insertAtEach 阶段将并行工作。
[C]
[BC] [CB]
[ABC] [BCA] [BCA] [ACB] [CAB] [CBA]
CPU01 CPU02
即使我们使用较大的初始列表(例如permute [0..9]),它实际上也更慢。我们还没有弄清楚withDegreeOfParallelism 和相关的 PSeq 选项是否会有所帮助。
一边
下面是其余的代码清单:
let put a q xs =
([], xs)
||> Seq.fold (fun acc x ->
if x = q then a::x::acc
else x::acc)
|> List.rev
// Insert x at each possible location in xs
let insertAtEach a xs =
([a::xs], xs)
||> Seq.fold (fun acc x ->
(put a x xs)::acc)
【问题讨论】:
-
据我了解,F# 并行代码的固定成本相对较高,即使使用
permute [0..9]也可能不足以克服固定成本。我建议首先进行多次测量:比较 8 个元素排列的串行与并行运行时间,然后是 9,然后是 10,然后是 11,然后是 12……并绘制时间图。看起来并行版本会一直领先于串行版本吗?那么并行版本效率低下可能有一些原因。但如果看起来并行版本最终会赶上来,那么它只是固定成本。 -
@rmunn 我需要用不同的方法来尝试,因为在现有的实现中,
permute [0..10]使用 Seq 或 PSeq 方法花费的时间太长(超过 15 分钟)尽管permute [0..9]只需要 15 秒左右。 -
@rmunn 虽然您所说的通常是正确的,但在这种特殊情况下,问题是 fold 原则上不可并行化。 :-)
标签: parallel-processing f# seq plinq