2012-07-09 6 views
7

zu verwenden Ich habe gerade begonnen, die TPL zu verwenden, und ich möchte mehrere Aufrufe an Web-Services parallel geschehen. Soweit ich das beurteilen kann, sehe ich zwei Möglichkeiten, dies zu tun.Was wäre eine bessere Möglichkeit, Task parallel Bibliothek

Entweder Parallel.ForEach:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere. 
     Parallel.ForEach(list, member => 
      { 
       var result = Proxy.Invoke(member); 
       //... 
       //Do stuff with the result 
       //... 
      }); 

Oder Task<T>:

List<ServiceMemberBase> list = new List<ServiceMemberBase>(); //Take list from somewhere. 
     ForEach(var member in list) 
     { 
      Task<MemberResult>.Factory.StartNew(() => proxy.Invoke(member)); 
     } 

     //Wait for all tasks to finish. 
     //Process the result objects. 

Ohne Berücksichtigung, wenn die Syntax korrekt ist oder nicht, werden diese equivilant?

Werden sie das gleiche Ergebnis liefern? Wenn nicht, warum? und was ist vorzuziehen?

Antwort

5

Für den Code und Anwendungsfall, die Sie diskutieren, sind die beiden Ansätze im Wesentlichen gleichwertig.

Parallel.ForEach ist nützlich, wenn Sie einen Eingabebereich über mehrere Tasks partitionieren müssen (hier nicht anwendbar) oder das Zusammenführen von Ergebnissen mehrerer unabhängiger paralleler Operationen (vielleicht hier anwendbar) einfacher zu synchronisieren ist.

In jedem Fall haben Sie richtig bemerkt, dass Sie im Fall Parallel.ForEach das Warten auf den Abschluss nicht manuell synchronisieren müssen. Wenn Sie Aufgaben manuell starten, müssen Sie diese Synchronisierung jedoch selbst verwalten. In diesem Fall würden Sie wahrscheinlich etwas wie Task.WaitAll(...) verwenden.

+0

Vielen Dank für die Antwort. Am Ende habe ich Parallel.ForEach verwendet und wir sehen eine Verbesserung der Reaktionszeit um 25% auf unserer Produktion - 16 Kernmaschinen.Ich vermute, dass der größte Teil des Gewinns in der parallelen Datenverarbeitung liegt und nicht in den parallelen Aufrufen der Webdienste selbst. –

1

Ohne zu reflektieren oder den Ausgang zu betrachten, konnte ich nicht mit Sicherheit sagen, ob die beiden gleich sind oder nicht; Ich würde allerdings bezweifeln, dass sie so verschieden sind. Die Frage, was besser ist, hängt vom Szenario ab. Um zu antworten, was vorzuziehen ist, ist wieder sehr subjektiv, in dem von Ihnen bereitgestellten Szenario würde ich sagen, dass ich die Parallel.ForEach bevorzugen würde, weil ich es lesen kann, aber wenn Ihr Entwicklungsteam nicht an die Parallelbibliothek gewöhnt ist, dann ist die zweite Version derjenige, für den man gehen sollte.

1

Zwischen den beiden Codeteilen wird Parallel.ForEach() effizienter sein, da es nacheinander mehrere Elemente in einem einzigen Task verarbeitet.

Aber beide verwenden so viele Threads wie die ThreadPool wird sie lassen, was in diesem Fall keine gute Idee ist. Das liegt daran, dass die ThreadPool die optimale Anzahl von Threads gut erraten kann, wenn Sie sehr kurze, CPU-gebundene Task s haben, was hier weit entfernt ist.

Aus diesem Grund denke ich, dass die beste Option, um den Grad der Parallelität auf eine kleine Zahl manuell zu begrenzen (Sie würden messen müssen, um herauszufinden, welche Zahl die besten Ergebnisse liefert):

List<ServiceMemberBase> list = …; //Take list from somewhere. 
Parallel.ForEach(list, new ParallelOptions { MaxDegreeOfParallelism = 10 }, 
member => 
{ 
    var result = Proxy.Invoke(member); 
    //... 
    //Do stuff with the result 
    //... 
}); 

Selbst effizienter wäre es, wenn Sie den Web-Service-Aufruf asynchron ausführen könnten. Dies zu tun und den Grad der Parallelität zur gleichen Zeit zu begrenzen, ist nicht sehr einfach, es sei denn, Sie sind auf C# 5. Wenn Sie auf C# 5 waren und Sie auch Proxy aktualisiert haben, um das Task-basierte asynchrone Muster (TAP) zu unterstützen Mit TPL Dataflow können Sie Ihren Code noch effizienter ausführen:

var actionBlock = new ActionBlock<ServiceMemberBase>(
    async member => 
    { 
     var result = await Proxy.InvokeAsync(member); 
     //... 
     //Do stuff with the result 
     //... 
    } 
    new ExecutionDataflowBlockOptions { MaxDegreeOfParallelism = 10 }); 
Verwandte Themen