Поведение цикла Parallel.ForEach - PullRequest
1 голос
/ 11 марта 2012

Это пример тестового приложения, в котором я пытаюсь изучить функциональность Parallel.Foreach Loop

static void Main(string[] args)
{
   List<string> Months = new List<string>()
   {
      "Jan", "Feb", "Mar", "Apr", "May", "June" 
   };
   Parallel.ForEach(Months, (x) => ProcessRandom(x));
   Console.ReadLine();
}

public static void ProcessRandom(string s)
{
     Random r = new Random();
     int i = r.Next(1, 100);
     Thread.Sleep(1000);
     Console.WriteLine(string.Format("Month Name {0} and Random ID assigned {1}", s, i));
}

Мое понимание параллельного foreach состоит в том, что он будет запускать метод ProcessRandom с параметром из списка параллельно.Все переменные внутри этого метода будут разделены, и они будут работать независимо друг от друга.Но когда я бегу, я вижу, что случайное значение, хранящееся в целом числе «i», показывает то же самое для пары записей из списка месяцев, и одно или может быть 2 будет иметь разные случайные значения.Почему это ведет себя так.Не должен параллельный цикл создавать новое случайное значение для каждой итерации.Если я использую ParallelOptions и устанавливаю MaxDegree of Parallelism в 1, тогда я вижу различные значения в переменной 'i'

Пожалуйста, помогите мне понять параллельные циклы.

1 Ответ

2 голосов
/ 11 марта 2012

Это происходит потому, что Random не совсем случайный, а псевдослучайный (http://msdn.microsoft.com/en-us/library/system.random.aspx). Эта проблема упоминается в комментариях к статье MSDN. Когда несколько экземпляров создаются одновременно и .Next () Это вызов в обоих случаях, возможно, они будут иметь один и тот же результат (из-за конечного разрешения системных часов). Чтобы справиться с этим, мы должны создать уникальное начальное число для каждой итерации. Для этого вы можете сделать что-то вроде этого ( но есть много способов снять шкуру с этой кошки):

static void Main(string[] args)
{
    List<string> Months = new List<string>() { "Jan", "Feb", "Mar", "Apr", "May", "June" };
    Parallel.ForEach(Months, (x) => ProcessRandom(x));
    Console.ReadLine();
}

public static void ProcessRandom(string s)
{            
    Random r = new Random(s.GetHashCode());
    int i = r.Next(1, 100);
    Thread.Sleep(1000);
    Console.WriteLine(string.Format("Month Name {0} and Random ID assigned {1}", s, i));
}

** Обратите внимание, что этот пример не гарантирует уникальность, а только показан как способ генерирования засеянного значения **

...