Wie kann ich diesen foreach-Code in Parallel.ForEach konvertieren?

180

Ich bin etwas verwirrt Parallel.ForEach.
Was ist Parallel.ForEachund was macht es genau?
Bitte verweisen Sie nicht auf einen MSDN-Link.

Hier ist ein einfaches Beispiel:

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);

foreach (string line in list_lines)
{
    //My Stuff
}

Wie kann ich dieses Beispiel umschreiben Parallel.ForEach?

SilverLight
quelle
Dies könnte hier beantwortet worden sein stackoverflow.com/questions/3789998/…
Ujjwal Manandhar
1
@UjjwalManandhar Das ist eigentlich ganz anders, da es um den Unterschied zwischen der ParallelKlasse und der Verwendung von PLINQ geht.
Reed Copsey
18
Andere haben geantwortet, wie Sie umschreiben können. Was macht es also? Es führt eine "Aktion" für jedes Element in der Sammlung aus, genau wie bei einem normalen Element foreach. Der Unterschied besteht darin, dass die parallele Version viele "Aktionen" gleichzeitig ausführen kann. In den meisten Fällen (abhängig davon, auf welchem ​​Computer der Code ausgeführt wird, wie beschäftigt er ist und andere Dinge) ist er schneller, und das ist der wichtigste Vorteil. Beachten Sie, dass Sie bei paralleler Ausführung nicht wissen können, in welcher Reihenfolge die Artikel verarbeitet werden. Mit einer normalen (seriellen) foreachist garantiert, dass lines[0]dann zuerst lines[1]kommt und so weiter.
Jeppe Stig Nielsen
1
@JeppeStigNielsen Es wird nicht immer schneller sein, da es einen erheblichen Aufwand gibt, Dinge parallel zu machen. Dies hängt von der Größe der Sammlung, auf der Sie iterieren, und der darin enthaltenen Aktion ab. Das Richtige ist, den Unterschied zwischen der Verwendung von Parallel.ForEach () und foreach () zu messen . Oft ist ein normales foreach () schneller.
Dave Black
3
@ DaveBlack Sicher. Man muss jeweils messen, ob es schneller oder langsamer ist. Ich habe nur versucht, die Parallelisierung im Allgemeinen zu beschreiben.
Jeppe Stig Nielsen

Antworten:

126
string[] lines = File.ReadAllLines(txtProxyListPath.Text);
List<string> list_lines = new List<string>(lines);
Parallel.ForEach(list_lines, line =>
{
    //Your stuff
});
PFUND
quelle
6
Ich wollte nur darauf hinweisen (mehr für das OP), damit es keinen fehlgeleiteten Gedanken gab, dass es nur funktioniert List<T>;)
Reed Copsey
1
Danke für die Aufmerksamkeit und Antwort. Ich habe List <string> in meinen Codes verwendet, weil ich doppelte Elemente mithilfe von HASH-Listen entfernt habe. Mit regulären Arrays können wir Duplikate nicht einfach entfernen :).
SilverLight
119
Ich bin verwirrt, dass diese Antwort als die richtige Antwort markiert ist, da es keine Erklärung für die ursprüngliche Frage "Was ist Parallel.ForEach und was macht es genau?"
Gibt.
6
@fosb Das Problem ist, dass der Titel der Frage bearbeitet wurde, um die Bedeutung vollständig zu ändern. Daher macht diese Antwort keinen Sinn mehr.
Trotzdem
273

Foreach-Schleife:

  • Die Iterationen erfolgen nacheinander
  • foreach-Schleife wird von einem einzelnen Thread ausgeführt.
  • foreach-Schleife ist in jedem Framework von .NET definiert
  • Die Ausführung langsamer Prozesse kann langsamer sein , da sie seriell ausgeführt werden
    • Prozess 2 kann erst gestartet werden, wenn 1 abgeschlossen ist. Prozess 3 kann erst gestartet werden, wenn 2 & 1 abgeschlossen sind ...
  • Die Ausführung schneller Prozesse kann schneller sein , da kein Threading-Overhead entsteht

Parallel.ForEach:

  • Die Ausführung erfolgt parallel.
  • Parallel.ForEach verwendet mehrere Threads.
  • Parallel.ForEach ist in .Net 4.0 und höher Frameworks definiert.
  • Die Ausführung langsamer Prozesse kann schneller sein , da sie parallel ausgeführt werden können
    • Die Prozesse 1, 2 und 3 können gleichzeitig ausgeführt werden (siehe wiederverwendete Threads im Beispiel unten).
  • Die Ausführung schneller Prozesse kann aufgrund des zusätzlichen Threading-Overheads langsamer sein

Das folgende Beispiel zeigt deutlich den Unterschied zwischen der herkömmlichen foreach-Schleife und

Beispiel Parallel.ForEach ()

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
namespace ParallelForEachExample
{
    class Program
    {
        static void Main()
        {
            string[] colors = {
                                  "1. Red",
                                  "2. Green",
                                  "3. Blue",
                                  "4. Yellow",
                                  "5. White",
                                  "6. Black",
                                  "7. Violet",
                                  "8. Brown",
                                  "9. Orange",
                                  "10. Pink"
                              };
            Console.WriteLine("Traditional foreach loop\n");
            //start the stopwatch for "for" loop
            var sw = Stopwatch.StartNew();
            foreach (string color in colors)
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            Console.WriteLine("foreach loop execution time = {0} seconds\n", sw.Elapsed.TotalSeconds);
            Console.WriteLine("Using Parallel.ForEach");
            //start the stopwatch for "Parallel.ForEach"
             sw = Stopwatch.StartNew();
            Parallel.ForEach(colors, color =>
            {
                Console.WriteLine("{0}, Thread Id= {1}", color, Thread.CurrentThread.ManagedThreadId);
                Thread.Sleep(10);
            }
            );
            Console.WriteLine("Parallel.ForEach() execution time = {0} seconds", sw.Elapsed.TotalSeconds);
            Console.Read();
        }
    }
}

Ausgabe

Traditional foreach loop
1. Red, Thread Id= 10
2. Green, Thread Id= 10
3. Blue, Thread Id= 10
4. Yellow, Thread Id= 10
5. White, Thread Id= 10
6. Black, Thread Id= 10
7. Violet, Thread Id= 10
8. Brown, Thread Id= 10
9. Orange, Thread Id= 10
10. Pink, Thread Id= 10
foreach loop execution time = 0.1054376 seconds

Verwenden des Beispiels Parallel.ForEach

1. Red, Thread Id= 10
3. Blue, Thread Id= 11
4. Yellow, Thread Id= 11
2. Green, Thread Id= 10
5. White, Thread Id= 12
7. Violet, Thread Id= 14
9. Orange, Thread Id= 13
6. Black, Thread Id= 11
8. Brown, Thread Id= 10
10. Pink, Thread Id= 12
Parallel.ForEach() execution time = 0.055976 seconds
Jignesh.Raj
quelle
62
Ich stimme Ihrer Behauptung, Parallel.ForEach sei (immer) schneller, nicht wirklich zu. Dies hängt wirklich von der Schwere des Betriebs innerhalb der Schleife ab. Dies kann den Aufwand für die Einführung von Paralellismus wert sein oder auch nicht.
Martao
1
Nun, die Parallele für jedes bedeutet, dass separate Threads eingerichtet werden, um den Code im Schleifenkörper auszuführen. Obwohl .NET über einen effizienten Mechanismus verfügt, ist dies ein erheblicher Aufwand. Wenn Sie also nur eine einfache Operation ausführen müssen (z. B. eine Summe oder Multiplikation), sollte die parallele foreach nicht schneller sein.
Martao
3
@Jignesh das ist nicht einmal ein gutes Messbeispiel, also würde ich überhaupt nicht darauf verweisen. Entfernen Sie "Thread.Sleep (10);" von jedem Schleifenkörper und versuchen Sie es erneut.
Stenly
1
@Martao ist richtig, das Problem liegt in den Overheads für die Objektsperre, bei denen der parallele Ansatz möglicherweise länger als sequentiell ist.
Stenly
8
@stenly Ich denke, der Schlaf ist genau der Grund, warum es ein gutes Beispiel ist. Sie würden kein PFE mit schnellen Einzeliterationen verwenden (wie Martao erklärte). Diese Antwort verlangsamt die Iteration und der (richtige) Vorteil von PFE wird hervorgehoben. Ich stimme jedoch zu, dass dies in der Antwort erklärt werden muss, ein kühnes "ist immer schneller" ist sehr irreführend.
Mafu
43
string[] lines = File.ReadAllLines(txtProxyListPath.Text);

// No need for the list
// List<string> list_lines = new List<string>(lines); 

Parallel.ForEach(lines, line =>
{
    //My Stuff
});

Dadurch werden die Zeilen innerhalb der Schleife parallel analysiert. Wenn Sie eine detailliertere, weniger "referenzorientierte" Einführung in die Parallel-Klasse wünschen, habe ich eine Reihe über die TPL geschrieben, die einen Abschnitt über Parallel.ForEach enthält .

Reed Copsey
quelle
9

Verwenden Sie für große Dateien den folgenden Code (Sie sind weniger speicherhungrig)

Parallel.ForEach(File.ReadLines(txtProxyListPath.Text), line => {
    //Your stuff
});
Samuel LEMAITRE
quelle
2

Diese Zeilen haben bei mir funktioniert.

string[] lines = File.ReadAllLines(txtProxyListPath.Text);
var options = new ParallelOptions { MaxDegreeOfParallelism = Environment.ProcessorCount * 10 };
Parallel.ForEach(lines , options, (item) =>
{
 //My Stuff
});
Prinz Prasad
quelle