Jak mogę ograniczyć Parallel.ForEach?

295

Mam pętlę asynchroniczną Parallel.ForEach (), z którą pobieram niektóre strony internetowe. Moja przepustowość jest ograniczona, więc mogę pobierać tylko x stron na raz, ale Parallel.ForEach wykonuje całą listę pożądanych stron internetowych.

Czy istnieje sposób ograniczenia liczby wątków lub dowolnego innego ogranicznika podczas uruchamiania Parallel.ForEach?

Kod demonstracyjny:

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

Prawdziwe zadanie nie ma nic wspólnego ze stronami, więc kreatywne rozwiązania do indeksowania stron internetowych nie pomogą.

eugeneK
źródło
@jKlaus Jeśli lista nie jest modyfikowana, np. jest to tylko zestaw adresów URL, naprawdę nie widzę problemu?
Shiv
@Shiv, biorąc pod uwagę wystarczającą ilość czasu, będziesz ... Policzyć swoją liczbę egzekucji i porównać ją z liczbą list.
jKlaus
@jKlaus Co mówisz, pójdzie nie tak?
Shiv
1
@ jKlaus modyfikujesz element inny niż bezpieczny (liczba całkowita). Spodziewałbym się, że to nie zadziała w tym scenariuszu. Z drugiej strony OP nie modyfikuje niczego, co musi być bezpieczne dla wątków.
Shiv
2
@jKlaus Oto przykład Parallel.ForEach, który poprawnie ustawia liczbę> dotnetfiddle.net/moqP2C . Link do MSDN: msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx
jhamm

Odpowiedzi:

564

Można określić MaxDegreeOfParallelismw ParallelOptionsparametrze:

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

MSDN: Parallel.ForEach

MSDN: ParallelOptions.MaxDegreeOfParallelism

Nicholas Butler
źródło
59
Może nie dotyczyć tego konkretnego przypadku, ale pomyślałem, że wyrzucę go na wypadek, gdyby ktoś się nad tym zastanawiał i uznał to za przydatne. Tutaj wykorzystuję 75% (w zaokrągleniu) liczby procesorów. var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) };
jKlaus,
4
Aby zaoszczędzić na tym, że ktokolwiek będzie musiał to sprawdzić w dokumentacji, przekazanie wartości -1jest takie samo, jak w ogóle jej nieokreślanie: „Jeśli [wartość] wynosi -1, nie ma ograniczenia liczby jednoczesnych uruchomionych operacji”
stuartd
Dokumentacja nie jest dla mnie jasna - czy ustawienie MaxDegreeOfParallelism na 4 (na przykład) oznacza, że ​​będą 4 wątki w każdym z 1/4 iteracji pętli (wysłana jedna runda 4 wątków), czy też każdy wątek nadal wykonuje jedną pętlę iteracja, a my ograniczamy tylko liczbę uruchomionych równolegle?
Hashman
7
Aby być czystym rdzenie i wątki to nie to samo. W zależności od procesora istnieje różna liczba wątków na rdzeń, zwykle 2 na rdzeń. Na przykład, jeśli masz 4-rdzeniowy procesor z 2 wątkami na rdzeń, to masz maksymalnie 8 wątków. Aby dostosować komentarz @jKlaus var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 2.0)) };. Link do wątków vs rdzenie - askubuntu.com/questions/668538/…
TheMiddleMan
41

Możesz użyć ParallelOptions i ustawić MaxDegreeOfParallelism, aby ograniczyć liczbę współbieżnych wątków:

Parallel.ForEach(
    listOfwebpages, 
    new ParallelOptions{MaxDegreeOfParallelism=2}, 
    webpage => {Download(webpage);});     
rikitikitik
źródło
21

Użyj innego przeciążenia, Parallel.Foreachktóre zajmuje ParallelOptionswystąpienie i ustaw, MaxDegreeOfParallelismaby ograniczyć liczbę wystąpień wykonywanych równolegle.

Richard
źródło
11

A dla użytkowników VB.net (składnia jest dziwna i trudna do znalezienia) ...

Parallel.ForEach(listOfWebpages, New ParallelOptions() With {.MaxDegreeOfParallelism = 8}, Sub(webpage)
......end sub)  
użytkownik3496060
źródło