Wird Parallel.ForEach in der Reihenfolge mit MaxDegreeOfParallelism = 1 arbeiten?

8

Ist Parallel.ForEach() mit MaxDegreeOfParallelism==1 garantiert, um die in der Reihenfolge aufzählbare Eingabe zu verarbeiten?

Wenn die Antwort "nein" lautet, gibt es eine Möglichkeit, dieses Verhalten zu erzwingen?

    
D.R. 15.03.2017, 13:42
quelle

2 Antworten

10

Erstens ist es richtig, dass die offizielle Dokumentation von Microsoft zur parallelen Programmierung angibt, dass die Ausführungsreihenfolge lautet nicht garantiert .

  

Die Methode "Parallel.ForEach" garantiert nicht die Reihenfolge der Ausführung. Im Gegensatz zu einer sequenziellen ForEach-Schleife werden die eingehenden Werte nicht immer in der richtigen Reihenfolge verarbeitet.

Am besten verwenden Sie Parallel.ForEach , da die öffentliche API so konzipiert ist: um Elemente parallel zu verarbeiten . Wenn Sie Elemente sequenziell verarbeiten müssen, ist es besser, eine normale foreach -Schleife zu verwenden. Die Absicht ist klarer als die Verwendung von MaxDegreeOfParallelism = 1 .

Um es kurz zu sagen, habe ich mir den Quellcode für .NET 4.7.1 angesehen. Die kurze Antwort ist ja, die Elemente werden sequentiell verarbeitet, wenn MaxDegreeOfParallelism = 1 . Sie sollten sich jedoch nicht auf zukünftige Implementierungen verlassen, da dies möglicherweise nicht immer so ist.

Werfen Sie einen Blick auf Parallel.ForEach und folgen Sie ihm, Sie werden schließlich sehen, dass die zu iterierende Sammlung partitioniert ist (dieser Prozess ist etwas anders, egal ob es ein TSource[] , List<TSource> oder ein IEnumerable<TSource> ist.

Task.SavedStateForNextReplica und Task.SavedStateFromPreviousReplica werden in ParallelForReplicaTask überschrieben, um den Status zwischen parallel ausgeführten Tasks zu kommunizieren. In diesem Fall werden sie verwendet, um zu kommunizieren, über welche Partition die Task iterieren soll.

Sehen wir uns schließlich Task.ExecuteSelfReplicating an. ParallelForReplicatingTask überschreibt ShouldReplicate basierend auf dem angegebenen Parallelitätsgrad sowie der MaximumConcurrencyLevel des Aufgabenplaners. Also wird dies mit MaxDegreeOfParallelism = 1 nur eine einzige untergeordnete Aufgabe erstellen. Daher wird diese Task nur über die einzelne Partition ausgeführt, die erstellt wurde.

Also, um Ihre Frage zu beantworten: ab dem Schreiben wird Parallel.ForEach mit MaxDegreeOfParallism = 1 die Auflistung auflisten von Anfang bis Ende für ein TSource[] , von Anfang bis Ende für ein IList<TSource> und verwenden Sie GetEnumerator für IEnumerable<TSource> , mit leicht unterschiedlichen Pfaden, abhängig davon, ob IEnumerable<TSource> in OrderablePartitioner<TSource> umgewandelt werden kann oder nicht. Diese drei Pfade sind in Parallel.ForEachWorker festgelegt.

Ich empfehle Ihnen dringend, selbst durch den Quellcode zu blättern, um selbst zu sehen.

Ich hoffe, dass dies Ihre Frage beantworten kann, aber es ist wirklich wichtig sich daran zu erinnern: Verlassen Sie sich nicht darauf . Es ist sehr wahrscheinlich, dass sich diese Implementierung in Zukunft ändern kann.

    
johnnyRose 16.02.2018 18:15
quelle
3

Von MSDN:

  

Die Methode "Parallel.ForEach" garantiert nicht die Reihenfolge der Ausführung. Im Gegensatz zu einer sequenziellen ForEach-Schleife werden die eingehenden Werte nicht immer in der richtigen Reihenfolge verarbeitet.

Ссылка

    
Sylence 16.02.2018 17:06
quelle

Tags und Links