it-swarm.com.de

Parallel.ForEach Langsamer als ForEach

Hier ist der Code:

using (var context = new AventureWorksDataContext())
{
    IEnumerable<Customer> _customerQuery = from c in context.Customers
                                           where c.FirstName.StartsWith("A")
                                           select c;

    var watch = new Stopwatch();
    watch.Start();

    var result = Parallel.ForEach(_customerQuery, c => Console.WriteLine(c.FirstName));

    watch.Stop();
    Debug.WriteLine(watch.ElapsedMilliseconds);

    watch = new Stopwatch();
    watch.Start();

    foreach (var customer in _customerQuery)
    {
        Console.WriteLine(customer.FirstName);
    }

    watch.Stop();
    Debug.WriteLine(watch.ElapsedMilliseconds);
}

Das Problem ist, dass Parallel.ForEach ungefähr 400 ms dauert, während eine reguläre foreach ungefähr 40 ms dauert. Was genau mache ich falsch und warum funktioniert das nicht so, wie ich es erwartet habe?

28
Mike Diaz

Angenommen, Sie müssen eine Aufgabe ausführen. Angenommen, Sie sind Mathematiklehrer und haben zwanzig Prüfungsarbeiten zu erledigen. Die Benotung eines Papiers dauert zwei Minuten, Sie brauchen also ungefähr vierzig Minuten.

Nehmen wir nun an, Sie möchten einige Assistenten einstellen, die Ihnen bei der Bewertung von Arbeiten helfen. Die Suche nach vier Assistenten dauert eine Stunde. Sie nehmen jeweils vier Papiere und sind in acht Minuten fertig. Sie haben 40 Minuten Arbeit für insgesamt 68 Minuten Arbeit einschließlich der zusätzlichen Stunde, um die Assistenten zu finden, eingetauscht. Dies ist also keine Einsparung. Der Aufwand für die Suche nach den Assistenten ist höher als die Kosten für die Arbeit selbst.

Angenommen, Sie haben zwanzigtausend Prüfungsarbeiten, sodass Sie ungefähr 40000 Minuten benötigen. Wenn Sie eine Stunde damit verbringen, Assistenten zu finden, ist das ein Gewinn. Sie nehmen jeweils 4000 Papiere und sind in insgesamt 8060 anstatt 40000 Minuten erledigt, was einer Ersparnis von fast dem Faktor 5 entspricht. Der Aufwand, die Assistenten zu finden, ist im Grunde genommen irrelevant.

Die Parallelisierung ist nicht frei. Die Kosten für die Aufteilung der Arbeit auf verschiedene Threads müssen im Vergleich zum Arbeitsaufwand pro Thread gering sein.

Weitere Lektüre:

https://en.wikipedia.org/wiki/Amdahl%27s_law

https://en.wikipedia.org/wiki/Gustafson%27s_law

142
Eric Lippert

Das erste, was Sie wissen sollten, ist, dass nicht jede Parallelität von Vorteil ist. Parallelität ist mit einem gewissen Overhead verbunden, und dieser Overhead kann je nach Komplexität der Parallelisierung erheblich sein oder auch nicht. Da die Arbeit in Ihrer parallelen Funktion sehr gering ist, wird der Verwaltungsaufwand, den die Parallelität zu leisten hat, erheblich und verlangsamt somit die Gesamtarbeit.

9
skaz

Der zusätzliche Aufwand für das Erstellen aller Threads für Ihr aufzählbares VS, das nur die numerische Datei ausführt, ist höchstwahrscheinlich die Ursache für die Verlangsamung. Parallel.ForEach ist kein pauschaler Zug zur Leistungssteigerung. Es muss abgewogen werden, ob die für jedes Element auszuführende Operation wahrscheinlich blockiert.

Wenn Sie beispielsweise eine Webanforderung oder etwas anderes stellen, anstatt einfach in die Konsole zu schreiben, ist die parallele Version möglicherweise schneller. Das einfache Schreiben in die Konsole ist ein sehr schneller Vorgang. Daher wird der Aufwand für das Erstellen und Starten der Threads langsamer.

9
Tejs

Wie der vorherige Autor bereits sagte, ist mit Parallel.ForEach ein gewisser Overhead verbunden, aber aus diesem Grund können Sie keine Leistungsverbesserung feststellen. Console.WriteLine ist eine synchrone Operation, daher arbeitet immer nur ein Thread gleichzeitig. Wenn Sie versuchen, den Körper in einen nicht blockierenden Zustand zu ändern, wird die Leistung gesteigert (solange der Arbeitsaufwand im Körper groß genug ist, um den Overhead zu überlasten).

4
salomons

Ich mag Salomons Antwort und möchte hinzufügen, dass Sie auch zusätzlichen Overhead von haben

  1. Zuweisen von Delegierten.
  2. Ich rufe durch sie.
0
Yola