2012-04-14 58 views
1

我正在玩並行編程和F#。我創建,集成有1可變功能的功能,然後我試圖使它平行於兩種不同的方式:並行代碼與Task.Factory比線性慢

module Quadrature = 

    let Integrate (f: double -> double) (x1: double) (x2: double) (samples: int64) = 
     let step = (x2 - x1)/(double samples) 
     let samplePoints = seq {x1 + step .. step .. x2 - step} 
     let sum = samplePoints |> Seq.map (fun x -> f x) |> Seq.sum 
     let sum = sum + ((f x1) + (f x2))/2.0 
     step * sum 

    let IntegrateWithStep (f: double -> double) (x1: double) (x2: double) (step: double) = 
     let samples = (x2 - x1)/step |> round |> int64 
     Integrate f x1 x2 samples 

    let IntegrateWithTasks (f: double -> double) (x1: double) (x2: double) (samples: int64) (tasks: int) = 
     let step = (x2 - x1)/(double samples) 
     let samplesPerTask = ceil <| (double samples)/(double tasks) 
     let interval = step * samplesPerTask 
     let intervals = 
      seq { 
       for i in 0 .. (tasks - 1) do 
        let lowerBound = x1 + (double i) * interval 
        let upperBound = min (lowerBound + interval) x2 
        yield (lowerBound, upperBound) 
       } 
     let tasks = intervals 
        |> Seq.map (fun (a, b) -> Task.Factory.StartNew(fun() -> IntegrateWithStep f a b step)) 
     tasks |> Seq.map (fun t -> t.Result) |> Seq.sum 

    let IntegrateParallel (f: double -> double) (x1: double) (x2: double) (samples: int64) (tasks: int) = 
     let step = (x2 - x1)/(double samples) 
     let samplesPerTask = ceil <| (double samples)/(double tasks) 
     let interval = step * samplesPerTask 
     let intervals = 
       [| for i in 0 .. (tasks - 1) do 
        let lowerBound = x1 + (double i) * interval 
        let upperBound = min (lowerBound + interval) x2 
        yield (lowerBound, upperBound) |] 
     intervals |> Array.Parallel.map (fun (a, b) -> IntegrateWithStep f a b step) 
        |> Array.sum 

運行此代碼與機器上的以下輸入與4芯:

let f = (fun x -> - 1.0 + 2.0 * x - 3.0 * x * x + 4.0 * x * x * x) 
let x1, x2 = 0.0, 1.0 
let samples = 100000000L 
let tasks = 100 

但是,使用任務工廠的方法總是比線性方法稍慢,而使用Parallel.map的方法則使我加快了速度。

我曾嘗試改變從數千下降到核心數量的任務數量,但與Task.Factory的實現總是比線性的慢。我究竟做錯了什麼?

回答

1

請記住,序列是延遲加載。這是第一次任務得到啓動:

tasks |> Seq.map (fun t -> t.Result) |> Seq.sum 

你依次開始他們並阻止每一個爲他們的結果調用t.Result時,(你要的任務列表保存爲一個數組,和。然後收集結果,以確保它們全部並行開始之前打電話.WaitAll

嘗試:

let tasks = intervals 
      |> Seq.map (fun (a, b) -> Task.Factory.StartNew(fun() -> IntegrateWithStep f a b step)) 
      |> Array.ofSeq 

tasks.WaitAll() 
+0

我修改了這一行'任務|> Seq.toArray |> Array.map(樂趣筆 - >。 t.Result)|> Array.sum',它現在給我加快了速度,謝謝! – Panos 2012-04-14 08:58:56