Wie kann ich Parallel.ForEach einschränken?


295

Ich habe eine asynchrone Parallel.ForEach () -Schleife, mit der ich einige Webseiten herunterlade. Meine Bandbreite ist begrenzt, so dass ich nur x Seiten pro Zeit herunterladen kann, aber Parallel.ForEach führt eine ganze Liste der gewünschten Webseiten aus.

Gibt es eine Möglichkeit, die Thread-Nummer oder einen anderen Begrenzer zu begrenzen, während Parallel.ForEach ausgeführt wird?

Demo-Code:

Parallel.ForEach(listOfWebpages, webpage => {
  Download(webpage);
});

Die eigentliche Aufgabe hat nichts mit Webseiten zu tun, sodass kreative Webcrawling-Lösungen nicht helfen.


@jKlaus Wenn die Liste nicht geändert wird, z. B. nur eine Reihe von URLs, kann ich das Problem nicht wirklich erkennen?
Shiv

@Shiv, wenn Sie genug Zeit haben, werden Sie ... Zählen Sie Ihre Anzahl von Ausführungen und vergleichen Sie sie mit der Anzahl der Listen.
jKlaus

@jKlaus Was sagst du wird schief gehen?
Shiv

1
@jKlaus Sie ändern ein nicht threadsicheres Element (die Ganzzahl). Ich würde erwarten, dass es in diesem Szenario nicht funktioniert. Das OP hingegen ändert nichts, was threadsicher sein muss.
Shiv

2
@jKlaus Hier ist ein Beispiel für Parallel.ForEach, das die Anzahl korrekt einstellt > dotnetfiddle.net/moqP2C . MSDN Link: msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx
jhamm

Antworten:


564

Sie können a MaxDegreeOfParallelismin einem ParallelOptionsParameter angeben :

Parallel.ForEach(
    listOfWebpages,
    new ParallelOptions { MaxDegreeOfParallelism = 4 },
    webpage => { Download(webpage); }
);

MSDN: Parallel.ForEach

MSDN: ParallelOptions.MaxDegreeOfParallelism


59
Es mag nicht auf diesen speziellen Fall zutreffen, aber ich dachte, ich würde es wegwerfen, falls sich jemand darüber wundert und es nützlich findet. Hier verwende ich 75% (aufgerundet) der Prozessoranzahl. var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) };
jKlaus

4
Um zu vermeiden, dass andere Personen in der Dokumentation nachschlagen müssen, entspricht das Übergeben eines Werts von -1dem, dass er überhaupt nicht angegeben wird: "Wenn [der Wert] -1 ist, gibt es keine Begrenzung für die Anzahl der gleichzeitig ausgeführten Vorgänge."
stuartd

Aus der Dokumentation ist mir nicht klar, ob das Setzen von MaxDegreeOfParallelism auf 4 (zum Beispiel) bedeutet, dass jeweils 4 Threads 1/4 der Schleifeniterationen ausführen (eine Runde mit 4 versendeten Threads), oder führt jeder Thread immer noch eine Schleife aus Iteration und wir begrenzen nur, wie viele parallel laufen?
Hashman

7
Klare Kerne und Fäden sind nicht dasselbe. Abhängig von der CPU gibt es eine unterschiedliche Anzahl von Threads pro Kern, normalerweise 2 pro Kern. Wenn Sie beispielsweise eine 4-Kern-CPU mit 2 Threads pro Kern haben, haben Sie maximal 8 Threads. Zum Anpassen des @ jKlaus-Kommentars var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 2.0)) };. Link zu Threads gegen Kerne - askubuntu.com/questions/668538/…
TheMiddleMan

41

Sie können ParallelOptions verwenden und MaxDegreeOfParallelism festlegen, um die Anzahl gleichzeitiger Threads zu begrenzen:

Parallel.ForEach(
    listOfwebpages, 
    new ParallelOptions{MaxDegreeOfParallelism=2}, 
    webpage => {Download(webpage);});     

21

Verwenden Sie eine andere Überladung Parallel.Foreach, die eine ParallelOptionsInstanz benötigt, und legen Sie fest MaxDegreeOfParallelism, wie viele Instanzen parallel ausgeführt werden sollen.


11

Und für die VB.net-Benutzer (Syntax ist seltsam und schwer zu finden) ...

Parallel.ForEach(listOfWebpages, New ParallelOptions() With {.MaxDegreeOfParallelism = 8}, Sub(webpage)
......end sub)  
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.