Parallel.For <int>не работает должным образом - PullRequest
0 голосов
/ 02 сентября 2018

Я написал простой цикл Parallel.For. Но когда я запускаю код, я получаю случайные результаты. Я ожидаю, что общая сумма будет 15 (1 + 2 + 3 + 4 + 5). Я использовал Interlocked.Add, чтобы предотвратить гонки и странное поведение. Может кто-нибудь объяснить, почему вывод случайный, а не 15?

public class Program
{
    public static void Main(string[] args)
    {
        Console.WriteLine("before Dowork");

        DoWork();
        Console.WriteLine("After Dowork");
        Console.ReadLine();
    }

    public static void DoWork()
    {
        try
        {
            int total = 0;
            var result = Parallel.For<int>(0, 6,
                () => 0,
                (i, status, y) =>
                {
                    return i;
                },
                (x) =>
                {
                    Interlocked.Add(ref total, x);
                });

            if (result.IsCompleted)
                 Console.WriteLine($"total is: {total}");
            else Console.WriteLine("loop not ready yet");
        }
        catch(Exception e)
        {
            Console.WriteLine(e.Message);
        }
    }
}

1 Ответ

0 голосов
/ 02 сентября 2018

Вместо использования

(i, status, y) =>
{
    return i;
}

вы должны использовать

(i, status, y) =>
{
    return y + i;
}

Parallel.For разбивает исходную последовательность на несколько разделов. Элементы в каждом разделе обрабатываются последовательно, но несколько разделов могут выполняться параллельно.

Каждый раздел имеет локальное состояние . Локальное состояние является возвращаемым значением вышеупомянутой лямбда-функции, и оно также передается как параметр y. Поэтому причина возврата y + i теперь должна быть понятна: вам нужно обновить локальное состояние до суммы предыдущего состояния и входного значения i.


После обработки каждого элемента раздела окончательное значение локального состояния передается последней функции, где вы суммируете все состояния:

(x) =>
{
    Interlocked.Add(ref total, x);
}
...