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.

eugeneK
quelle
@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

Nicholas Butler
quelle
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);});     
rikitikitik
quelle
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.

Richard
quelle
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)  
user3496060
quelle