Як я можу обмежити Parallel.ForEach?


295

У мене є цикл асинхронізації Parallel.ForEach (), за допомогою якого я завантажую деякі веб-сторінки. Моя пропускна здатність обмежена, тому я можу завантажувати лише x сторінок за раз, але Parallel.ForEach виконує весь список потрібних веб-сторінок.

Чи є спосіб обмежити кількість потоку або будь-який інший обмежувач під час роботи Parallel.ForEach?

Демо-код:

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

Справжнє завдання не має нічого спільного з веб-сторінками, тому креативні рішення веб-сканування не допоможуть.


@jKlaus Якщо список не змінено, наприклад, це лише набір URL-адрес, я не можу побачити проблему?
Шив

@Shiv, давши достатньо часу, ти будеш ... Порахувати свою кількість страт і порівняти її з кількістю списку.
jKlaus

@jKlaus Що ти кажеш, піде не так?
Шив

1
@jKlaus ви змінюєте елемент, який не є безпечним потоком (ціле число). Я б очікував, що це не працюватиме за таким сценарієм. З іншого боку, ОП не змінює нічого, що повинно бути безпечним для потоків.
Шив

2
@jKlaus Ось приклад Parallel.ForEach, який правильно встановлює підрахунок> dotnetfiddle.net/moqP2C . MSDN Посилання: msdn.microsoft.com/en-us/library/dd997393(v=vs.110).aspx
jhamm

Відповіді:


564

Ви можете вказати MaxDegreeOfParallelismв ParallelOptionsпараметрі:

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

MSDN: Parallel.ForEach

MSDN: ParallelOptions.MaxDegreeOfParallelism


59
Це може не стосуватися цього конкретного випадку, але я подумав, що викину його, якщо хтось задумається про це і виявить це корисним. Тут я використовую 75% (округлений) кількості процесора. var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 1.0)) };
jKlaus

4
Тільки для того, щоб врятувати когось іншого, який потребує його пошуку в документації, передача значення - -1це те саме, що зовсім не вказати його: "Якщо [значення] -1, немає обмеження кількості одночасно виконуваних операцій"
stuartd

Мені незрозуміло з документації - чи означає, що встановлення MaxDegreeOfParallelism на 4 (наприклад) означає, що буде 4 нитки, що виконуються 1/4 ітерації циклу (один раунд із 4-х потоків, що надсилаються), чи кожен потік все ще робить одну петлю ітерація, і ми просто обмежуємо кількість бігу паралельно?
Хашман

7
Ясні ядра та нитки - це не одне і те ж. Залежно від процесора, існує різна кількість потоків на ядро, як правило, 2 на ядро. Наприклад, якщо у вас є 4-ядерний процесор з 2 потоками на ядро, то у вас є максимум 8 потоків. Щоб налаштувати @jKlaus коментар var opts = new ParallelOptions { MaxDegreeOfParallelism = Convert.ToInt32(Math.Ceiling((Environment.ProcessorCount * 0.75) * 2.0)) };. Посилання на теми проти ядер - askubuntu.com/questions/668538/…
TheMiddleMan

41

Ви можете використовувати ParallelOptions і встановити MaxDegreeOfParallelism для обмеження кількості одночасних потоків:

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

21

Використовуйте ще одне перевантаження, Parallel.Foreachяке займає ParallelOptionsекземпляр, і встановіть MaxDegreeOfParallelismобмеження на кількість екземплярів, які виконуються паралельно.


11

А для користувачів VB.net (синтаксис дивний і важко знайти) ...

Parallel.ForEach(listOfWebpages, New ParallelOptions() With {.MaxDegreeOfParallelism = 8}, Sub(webpage)
......end sub)  
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.