F#Async.Parallel会加速计算吗?

时间:2011-01-31 14:03:33

标签: f# parallel-processing

“Async.Parallel”结构真的有助于在多核系统上更快地进行计算吗? .NET TPL“任务”是否以某种方式涉及到这里?

open System;

let key = Console.ReadKey(true);
let start = System.DateTime.Now

let pmap f l = seq { for a in l do yield async {return f a} } |> Async.Parallel |> Async.RunSynchronously
let map f l = seq {for a in l do yield f a}

let work f l = 
 match key.KeyChar with 
  | '1' -> pmap f l  
  | '2' -> Seq.toArray (map f l) 
  | _ -> [||]

let result = work (fun x -> (x * x) / 75) (seq { 1 .. 100000*3})
let endtime = DateTime.Now - start 

printfn "%A"endtime;
let pause = Console.ReadKey(true);

我想你们中的一些人会在理论上解释它,但我也会欣赏一些现实世界的测试。

3 个答案:

答案 0 :(得分:12)

仅当任务执行更复杂的操作时,才使用F#async进行纯粹的CPU绑定任务。如果您正在尝试并行执行非常简单的代码,那么最好使用PLINQ(和任务并行库),它们针对这类问题进行了更优化。

然而,即便如此,在一个微不足道的情况下获得加速是很困难的。如果您想再尝试一下,可以试试这个:

// Turn on timing in F# interactive
#time 
let data = [| 1 .. 5000000*3 |]

// Use standard 'map' function for arrays
let result = Array.map (fun x -> (x * x) / 75) data 
// Use optimized parallel version
let result = Array.Parallel.map (fun x -> (x * x) / 75) data

请注意,使用Array.map本身比使用序列表达式然后将结果转换为数组要快得多。如果您想使用比映射更复杂的操作,那么F#PowerPack包含PSeq模块,其功能类似于SeqList中的功能:

#r @"FSharp.PowerPack.Parallel.Seq.dll"

data 
|> PSeq.map (fun a -> ...)
|> PSeq.filter (fun a -> ...)
|> PSeq.sort
|> Array.ofSeq

如果您想了解更多相关信息,我最近写了一篇关于parallel programming in F#的博客系列。

答案 1 :(得分:9)

pmap正在做的是创建一个包含300,000个任务对象的列表,安排它们并行运行,然后才实际并行运行它们。换句话说,一个线程将在那里创建300,000个对象并将它们排队到线程池中。只有这样他们才能执行。

由于你的任务是如此微不足道(乘法和除法),创建任务,安排任务和处理结果的开销不仅仅是运行计算。这意味着async隐喻不适合此操作。为此使用PLINQ要好得多。

答案 2 :(得分:3)

通过计算这么简单,更好的方法是只创建一些异步线程(可能每个cpu一个),然后分别计算答案的一部分。正如Gabe回答的那样,您将花费所有时间来创建任务对象。

使用这种类型的计划,我得到的速度与CPU的数量非常接近(我尝试的最多是8 ......我意识到它不会永远扩展)

编写一个实用程序来执行此操作比调用PLINQ更重要,我想,但是一旦有了pmap类型实用程序,就可以轻松地重用它。