Das erste ist eine viel bessere Option.
Parallel.ForEach verwendet intern a Partitioner<T>
, um Ihre Sammlung in Arbeitselemente zu verteilen. Es wird nicht eine Aufgabe pro Element ausgeführt, sondern diese stapelweise ausgeführt, um den damit verbundenen Overhead zu verringern.
Mit der zweiten Option wird eine einzelne Task
pro Artikel in Ihrer Sammlung geplant. Während die Ergebnisse (fast) gleich sind, führt dies zu einem weitaus höheren Overhead als erforderlich, insbesondere bei großen Sammlungen, und führt dazu, dass die Gesamtlaufzeiten langsamer sind.
Zu Ihrer Information - Der verwendete Partitionierer kann gesteuert werden, indem die entsprechenden Überlastungen für Parallel.ForEach verwendet werden , falls dies gewünscht wird. Weitere Informationen finden Sie unter Benutzerdefinierte Partitionierer in MSDN.
Der Hauptunterschied zur Laufzeit besteht darin, dass der zweite asynchron wirkt. Dies kann mit Parallel.ForEach dupliziert werden, indem Sie Folgendes tun:
Task.Factory.StartNew( () => Parallel.ForEach<Item>(items, item => DoSomething(item)));
Auf diese Weise nutzen Sie weiterhin die Partitionierer, blockieren jedoch erst, wenn der Vorgang abgeschlossen ist.
Ich habe ein kleines Experiment durchgeführt, bei dem eine Methode "1.000.000.000 (eine Milliarde)" Mal mit "Parallel.For" und eine mit "Task" -Objekten ausgeführt wurde.
Ich habe die Prozessorzeit gemessen und Parallel effizienter gefunden. Parallel.Für unterteilt Ihre Aufgabe in kleine Arbeitselemente und führt sie auf allen Kernen parallel auf optimale Weise aus. Beim Erstellen vieler Aufgabenobjekte (FYI TPL verwendet intern das Thread-Pooling) wird jede Ausführung für jede Aufgabe verschoben, wodurch mehr Stress in der Box entsteht, was aus dem folgenden Experiment hervorgeht.
Ich habe auch ein kleines Video erstellt, das die grundlegende TPL erklärt und zeigt, wie Parallel.For Ihren Kern im Vergleich zu normalen Aufgaben und Threads effizienter nutzt. Http://www.youtube.com/watch?v=No7QqSc5cl8 .
Versuch 1
Experiment 2
quelle
Mehthod1()
in diesem Beispiel?Parallel.ForEach optimiert (startet möglicherweise nicht einmal neue Threads) und blockiert, bis die Schleife beendet ist, und Task.Factory erstellt explizit eine neue Taskinstanz für jedes Element und kehrt zurück, bevor sie beendet sind (asynchrone Tasks). Parallel.Foreach ist viel effizienter.
quelle
Meiner Ansicht nach ist das realistischste Szenario, wenn Aufgaben schwer zu erledigen sind. Shivprasads Ansatz konzentriert sich mehr auf die Objekterstellung / Speicherzuweisung als auf das Rechnen selbst. Ich habe eine Untersuchung durchgeführt, bei der die folgende Methode aufgerufen wurde:
Die Ausführung dieser Methode dauert ca. 0,5 Sekunden.
Ich habe es 200 Mal mit Parallel aufgerufen:
Dann habe ich es 200 Mal auf altmodische Weise genannt:
Der erste Fall wurde in 26656 ms abgeschlossen, der zweite in 24478 ms. Ich habe es viele Male wiederholt. Jedes Mal ist der zweite Ansatz geringfügig schneller.
quelle