F#中列表上的计算绑定并行处理选项

时间:2010-11-19 09:12:10

标签: f# asynchronous parallel-processing

async {}工作流程易于使用,并在IO等异步操作上提供了良好的结果。对于纯粹的数据绑定操作,这是一个很好的选择吗? .NET ThreadPool和BackgroundWorker也是数据绑定计算的更好选择吗?

我的例子是一个大型列表,大约10,000个字符串都是唯一的。对于每个项目,我需要比较字符串以及列表中后面的所有字符串。返回类型将是list<string * list<string>>,其中包含每个原始项以及可能的解决方案列表(可能的字符串匹配,基于某些特定于应用程序的算法)。

我最初的想法是使用ansyc {}工作流程,但我不确定这个问题是否更适合其他并行技术,或者即使它应该被平行化。

4 个答案:

答案 0 :(得分:3)

有几个选项,但第一个问题是您是否要使用基于任务或数据并行的解决方案。我最近写了一篇few articles about parallel programming in F#,所以你可能会发现这个系列中的一些文章很有用。

数据并行即可。如果你有一个纯粹的CPU绑定操作 data-parallel ,那么最好的选项是

  • 如果您有更复杂的声明性数据处理,请使用F# PowerPack中的PSeq模块。您可以在我的文章Using PLINQ and Tasks from F#中找到介绍。
  • 如果您只需要一个简单的地图操作,请使用标准F#librar中的Array.Parallel.map功能。

基于任务的CPU绑定。如果数据并行不能很好地解决您的问题,那么您可以使用.NET 4.0 Tasks或F#异步工作流和StartAsChild成员。任务不支持取消,并且在F#中看起来有点难看,但它们可能更加优化(如果你想创建非常多的它们)。另一方面,F#异步工作流在F#中看起来更优雅。我写了两篇比较选项的文章。 first one解释了基本功能和the second one关于取消的说明。

还有使用F#代理的消息传递,如果您需要复杂的协调(并且使用大量同步原语和可变状态编写),这可能会很好地工作 p>

答案 1 :(得分:1)

您的问题是CPU密集型的,因为您的所有数据都在内存中,主CPU成本是您自定义的字符串匹配算法。

您可以使用Parallel.For,这比CPU绑定并行任务的Async快一点。

答案 2 :(得分:0)

  

async {}工作流程易于使用,并在IO等异步操作上提供了良好的结果。对纯粹的数据绑定操作来说,这是一个不错的选择吗?

没有。异步用于并发IO,这与并行CPU绑定计算的问题完全不同。

  

.NET ThreadPool和BackgroundWorker也是数据绑定计算的更好选择吗?

略好一点,但它们仍然没有为此而建。

  

list<(string * list)

这不是有效的类型。

  

我最初的想法是使用ansyc {}工作流程

糟糕的主意。

  

但我不确定这个问题是否更适合其他并行技术,或者它是否应该被平行化。

首先编写正确的串行版本,如果速度太慢,请对其进行优化并将其并行化。例如,当您仍在使用链接列表时,您不太可能从并行性中看到显着的收益。

您描述的算法可以在F#中实现如下:

let rec f p a = function
  | [] -> List.rev a
  | x::xs -> f p ((x, List.filter (p x) xs)::a) xs

其中p是任意谓词函数,您的算法是通用的。例如,以下内容查找所有后续字符串等于每个头字符串:

> f (=) [] ["a"; "b"; "c"; "a"; "c"];;
val it : (string * string list) list =
  [("a", ["a"]); ("b", []); ("c", ["c"]); ("a", []); ("c", [])]

在我的上网本上运行10,000个字符串需要不到6秒。这够快吗?

答案 3 :(得分:0)

Async适用于并行CPU绑定操作和异步IO操作,适用于两者。 Don Syme对此有一个blog post。操作仍将在线程池上运行,因此您不会通过使用异步来放弃它。