Comment puis-je limiter Parallel.ForEach?

295

J'ai une boucle asynchrone Parallel.ForEach () avec laquelle je télécharge des pages Web. Ma bande passante est limitée, je ne peux donc télécharger que x pages à la fois, mais Parallel.ForEach exécute toute la liste des pages Web souhaitées.

Existe-t-il un moyen de limiter le nombre de threads ou tout autre limiteur lors de l'exécution de Parallel.ForEach?

Code de démonstration:

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

La vraie tâche n'a rien à voir avec les pages Web, donc les solutions créatives d'exploration de sites Web n'aideront pas.

eugeneK
la source
@jKlaus Si la liste n'est pas modifiée, par exemple, c'est juste un ensemble d'URL, je ne vois pas vraiment le problème?
Shiv
@Shiv, si vous disposez de suffisamment de temps ... Comptez votre nombre d'exécutions et comparez-le au nombre de la liste.
jKlaus
@jKlaus Que dites-vous qui ne va pas?
Shiv
1
@jKlaus vous modifiez un élément non threadsafe (l'entier). Je m'attendrais à ce qu'il ne fonctionne pas dans ce scénario. L'OP, d'autre part, ne modifie rien qui doit être threadsafe.
Shiv
2
@jKlaus Voici un exemple de Parallel.ForEach qui définit correctement le nombre> dotnetfiddle.net/moqP2C . Lien MSDN: msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx
jhamm

Réponses:

564

Vous pouvez spécifier un MaxDegreeOfParallelismdans un ParallelOptionsparamètre:

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

MSDN: Parallel.ForEach

MSDN: ParallelOptions.MaxDegreeOfParallelism

Nicholas Butler
la source
59
Cela peut ne pas s'appliquer à ce cas particulier, mais j'ai pensé que je le jeterais au cas où quelqu'un se poserait la question et le trouverait utile. Ici, j'utilise 75% (arrondi) du nombre de processeurs. var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) };
jKlaus
4
Juste pour éviter que quelqu'un d'autre doive le rechercher dans la documentation, transmettre une valeur de -1revient à ne pas le spécifier du tout: "Si [la valeur] est -1, il n'y a pas de limite sur le nombre d'opérations exécutées simultanément"
stuartd
La documentation ne m'apparaît pas clairement - la définition de MaxDegreeOfParallelism sur 4 (par exemple) signifie-t-il qu'il y aura 4 threads exécutant chacun 1/4 des itérations de boucle (un tour de 4 threads distribué), ou chaque thread fait-il toujours une boucle itération et nous limitons simplement le nombre d'exécutions en parallèle?
Hashman
7
Pour être clair, les noyaux et les threads ne sont pas la même chose. Selon le processeur, il existe un nombre différent de threads par cœur, généralement 2 par cœur. Par exemple, si vous avez un processeur à 4 cœurs avec 2 threads par cœur, vous disposez d'un maximum de 8 threads. Pour ajuster le commentaire @jKlaus var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 2.0)) };. Lien vers les fils vs les cœurs - askubuntu.com/questions/668538/…
TheMiddleMan
41

Vous pouvez utiliser ParallelOptions et définir MaxDegreeOfParallelism pour limiter le nombre de threads simultanés:

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

Utilisez une autre surcharge Parallel.Foreachqui prend une ParallelOptionsinstance et définissez-la MaxDegreeOfParallelismpour limiter le nombre d'instances exécutées en parallèle.

Richard
la source
11

Et pour les utilisateurs de VB.net (la syntaxe est bizarre et difficile à trouver) ...

Parallel.ForEach(listOfWebpages, New ParallelOptions() With {.MaxDegreeOfParallelism = 8}, Sub(webpage)
......end sub)  
user3496060
la source