5

Guten Tag,Ist Parallel.ForEach veraltet. alt, aus der Mode?

Parallele Ausführung kann durch mehrere Möglichkeiten erreicht werden. Vom rein manuellen "Multithreading" bis zur Verwendung verschiedener "Helfer" von Microsoft. Einer dieser Helfer ist die Parallel-Klasse.

Einer meiner Kollegen besteht darauf, dass Parallel.ForEach (oder Parallel-Klasse insgesamt) ist "alt" und sollte nicht verwendet werden. Stattdessen, sagt er, sollte man asynchrone Operationen verwenden. Mit anderen Worten sollten Sie Task.WhenAll() anstelle von Parallel.ForEach() verwenden.

die Frage, warum Parallel.ForEach(), nicht verwenden, wenn dies ist genau das, was nötig war - mehr teueren Operationen parallel ausgeführt, antwortete er, dass Parallel.ForEach() alt ist und dass Microsoft mit Asynchron/erwarten empfiehlt, wo immer möglich.

Ich suchte überall auf MSDN und Stackoverflow und überall konnte ich, aber ich konnte nichts finden, das auf die Notwendigkeit des Verwendens async/erwarten statt .Parallel verweist. Obwohl Sie oft ähnliche Ergebnisse erzielen können, wenn Sie diese Werkzeuge austauschen, bedeutet dies nicht, dass Parallel.ForEach veraltet ist. Oder tut es?

Jeder hat einen Link zu einigen "Best Practices" oder "Empfehlungen" von einem seriösen Gremium (MSDN?), Das würde sagen, dass Parallel.ForEach() wird auslaufen und man muss mit dem Erstellen, Ausführen und Warten auf Aufgaben bleiben?

Bitte posten Sie keine Antworten zu Parallel VS Async für dies als das ist nicht die Frage.

Die Frage ist: Da Sie können Aufgaben parallel mit Asynchron laufen make/erwarten WhenAll (WaitAll etc.), ist es 'Parallel' Klasse veraltet, alt, oder nicht in Mode in .NET 4.5 weiter machen?

+7

Wenn er behauptet, dass "Microsoft empfiehlt", dann sollte er in der Lage sein, diese Empfehlung zu zeigen. So etwas habe ich selbst nicht gesehen. –

+2

Ihr Freund verwirrt die Parallelität mit der Asynchronität. – dcastro

+0

@JonSkeet Sie sehen, ich möchte ihn nicht um Beweise bitten, bevor ich tatsächlich meine Forschung betreibe, weil ich nicht feindselig erscheinen möchte. Was ist, wenn deine Antwort (oder jemand anderes) "sicher ist, jeder weiß, dass es obsolet ist - wir behalten es nur für ältere Leute"? – agfc

Antwort

5

Ich glaube nicht Parallel.ForEach ist veraltet.

Seit Einführung der Task Parallel Library (TPL) mit .NET 4 hat Microsoft distinguished between "Data Parallelism" (e.g. Parallel.ForEach) and "Task Parallelism" (Task). Von MSDN:

  • "Datenparallelismus bezieht sich auf Szenarien, in denen der gleiche Vorgang gleichzeitig durchgeführt wird (das heißt, parallel ) auf Elemente in einer Quellensammlung oder Array".
  • "[T] fragen Parallelität bezieht sich auf eine oder mehrere unabhängige Aufgaben unter gleichzeitig."

(Hervorhebung durch mich wie dcastro commented (above). "Ihr Freund ist verwirrend Parallelität mit Asynchronität.")

Diese beiden Arten von Parallelität/Parallelität unterschiedliche Ziele verfolgen, so dass die TPL bietet für jede von ihnen unterschiedliche Fähigkeiten.

Konzeptionell gehört Task.WhenAll in die Aufgabe Parallelitätskategorie, also glaube ich nicht, dass es etwas veraltet, das zu der anderen (Datenparallelismus) -Kategorie gehört.

+0

Danke. In meinem Fall rufe ich mehrere externe Anrufe zu verschiedenen Quellen auf. Diese Anrufe sind völlig unabhängig voneinander. Ich kann jedoch nicht fortfahren, bevor alle fertig sind. Sowohl Parallel.ForEach als auch Task.WhenAll funktionieren hier einwandfrei. Allerdings finde ich, dass ParallelForEach eleganter ist und weniger Code beinhaltet. Seine Meinung ist, dass ja, vielleicht ist es nicht unbedingt falsch, es zu verwenden, aber die bevorzugte Methode ist Task.WhenAll(). – agfc

+0

@AlexeiFimine: Einige allgemeine Ratschläge zu Meinungsverschiedenheiten: Fragen Sie Ihren Kollegen * warum * er behauptet, dass "Task.WhenAll" bevorzugt wird. Während es in solchen Fällen oft kein klares Richtig und Falsch gibt, sollten Menschen in der Lage sein, ihre Ansprüche rational zu sichern. (Siehe [Jon Skeets Kommentar oben.] (Http: // stackoverflow.com/questions/29919727/29919803 # comment47960546_29919727)) Wenn seine Argumente dich überzeugen (d. h. sie sind "besser" als deine aktuelle Meinung), ändere deinen Code. Wenn Sie denken, dass Sie das bessere Argument haben ("eleganterer Code mit Parallel.ForEach"), bleiben Sie bei Ihrer Version des Codes. – stakx

2

Parallel.ForEach (und PLINQ als Ganzes) verfügt über Fähigkeiten, die nicht in der async Sprachunterstützung verfügbar sind.

Zum Beispiel können Sie den Grad der Parallelität begrenzen (z. B. 100 Elemente zu verarbeiten, aber nicht mehr als 10 zu einer Zeit). So ist es nicht obsolet.

Grundsätzlich async geht es darum, gleichzeitige Operationen - ohne irgendwelche Annahmen von Threading - einfacher zu schreiben. PLINQ beschäftigt sich mit der Berechnung von vielen Kernen.

Ich vermute, dass Ihr Kollege liest zu viel in direkte Verwendung von Task Parallel Library (TPL) mit async in der Sprache weitgehend unnötig (mit Ausnahme der Rückgabetyp von async Funktionen). Aber PLINQ war immer eine andere Schicht als TPL. Wenn etwas PLINQ und async sind zwei separate Möglichkeiten, TPL für verschiedene Zwecke zu verwenden.

+0

Gut mit dem DegreeOfParallelism. Ich fand es immer nützlich in der Art, wie es implementiert wird. Ich würde es manchmal sogar zum Testen und Debuggen verwenden wie in #If Debug .DegreeOfParallelism = 1 – agfc

2

async und await haben nichts mit Parallelität zu tun. Sie sind Technologien, mit denen vorhandene asynchrone APIs leichter konsumiert und verfügbar gemacht werden können. async und await keine Parallelität oder Parallelität initiieren. In der Tat await endet Parallelität durch Warten auf etwas, das bereits läuft.

Parallel.ForEach wird verwendet, um eine Reihe von homogenen Objekten auf die gleiche Weise auf mehreren Kernen zu verarbeiten. Sie können Parallel.ForEach simulieren, indem Sie eine große Anzahl von Aufgaben erzeugen. Das hat keinen Vorteil. Tatsächlich führt es Ineffizienzen ein und verschleiert den Code. Es ist möglich und funktioniert, aber es ist eine minderwertige Art, Dinge zu tun, wenn Parallel.ForEach anwendbar ist.

Ich denke, Ihr Kollege versteht nicht, dass warten wirklich nur wartet. Es startet nichts.

Verwenden Sie Parallel. * Und PLINQ (meistens) für CPU-gebundene Arbeit.

+1

warten Task.WhenAll (IEnumerable Tasks) wird tatsächlich alle Aufgaben in der Tasks-Sammlung parallel starten und dann auf alle von ihnen warten Komplett. Dieses Design macht genau das, was ParallelForEach tun würde. Um dies zu erreichen, müsste ich eine Liste dieser Aufgaben manuell erstellen. Es gibt auch das Problem, "aus dem Async herauszukommen". Es sieht viel intuitiver und sauberer aus, Parallel.ForEach in meinem Fall zu verwenden. – agfc

+0

@AlexeiFimine ** Nein! ** Es wird tun, was der Name sagt. Es wartet. Die Aufgaben müssen bereits ausgeführt werden. Aber Ihre Schlussfolgerung ist richtig: Warum Aufgaben für CPU-gebundene Arbeit zu verwalten, wenn Sie nur Parallel verwenden können. – usr

+0

@AlexeiFimine Diese Aufgaben wurden * wahrscheinlich *, aber nicht notwendigerweise, bei der ersten Erstellung gestartet. "Task.WhenAll" startet sie nicht, und 'wartet 'auch nicht, wie usr darauf hingewiesen hat. Es gibt absolut keine Garantie dafür, dass diese Aufgaben parallel verarbeitet werden oder dass sie tatsächlich asynchron sind - nach allem, was wir wissen, könnten sie synchron und sequenziell ausgeführt werden. Wiederum warten alle abwarten. – dcastro