2012-04-14 8 views
1

Ich spiele mit paralleler Programmierung und F #. Ich habe eine Funktion, die eine 1-variable-Funktion integriert, und dann habe ich versucht, um es auf zwei verschiedene Arten zu machen Parallel:Paralleler Code mit Task.Factory langsamer als linear

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 

ich diesen Code mit der folgenden Eingabe mit 4 Kernen auf einer Maschine ausgeführt werden:

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 

Allerdings ist die Methode mit der Task Factory immer etwas langsamer als die lineare, während die mit der Parallel.map mir eine gute Geschwindigkeit gibt.

Ich habe versucht, die Anzahl der Aufgaben von Tausenden auf die Anzahl der Kerne zu variieren, aber die Implementierung mit der Task.Factory ist immer langsamer als die lineare. Was mache ich falsch?

Antwort

1

Denken Sie daran, dass die Sequenzen lazy geladen sind. Hier ist das erste Mal, wird die Aufgabe gestartet:

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

Und Sie beginnen, sie nacheinander und jeder für ihr Ergebnis blockiert (wenn t.Result Aufruf Sie finden die Liste der Aufgaben als Array gespeichert werden soll, und. rufen dann .WaitAll bevor die Ergebnisse zu sammeln, um sicherzustellen, dass sie alle parallel loszulegen

Versuchen:

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

tasks.WaitAll() 
+0

ich diese Zeile geändert 'Aufgaben |> Seq.toArray |> Array.map (fun t ->. t.Result) || Array.sum' und es gibt mir jetzt eine Beschleunigung. Danke! – Panos

Verwandte Themen