2010-07-31 9 views
2

Я грубо-принудительное суммирование всех простых чисел до 2000000. После этого, просто для удовольствия я пытался параллельно, но я был немного удивлен, когда увидел, что Parallel.For дает мне неверно сумма!.Net Parallel.For странное поведение

Вот мой код: (C#)

static class Problem 
{ 
    public static long Solution() 
    { 
     long sum = 0; 
     //Correct result is 142913828922 
     //Parallel.For(2, 2000000, i => 
     //        { 
     //         if (IsPrime(i)) sum += i; 
     //        }); 
     for (int i = 2; i < 2000000; i++) 
     { 
      if (IsPrime(i)) sum += i; 
     } 
     return sum; 
    } 
    private static bool IsPrime(int value) 
    { 
     for (int i = 2; i <= (int)Math.Sqrt(value); i++) 
     { 
      if (value % i == 0) return false; 
     } 
     return true; 
    } 
} 

Я знаю, что перебор очень плохое решения здесь, но это не вопрос о том. Думаю, я совершил очень тупую ошибку, но я просто не могу ее найти. Итак, for вычисляется правильно, но Parallel.For нет.

+2

Возможный дубликат [Parallel.For(): обновить переменную за пределами цикла] (http://stackoverflow.com/questions/2774170/parallel-for-update-variable-outside-of-loop) –

+1

И точный дубликат [Различные результаты суммирования с Parallel.ForEach] (http://stackoverflow.com/questions/3367293/different-summation-results-with-parallel-foreach/3367311#3367311) –

ответ

4

Вы получаете доступ к переменной сумме из нескольких потоков без ее блокировки, поэтому возможно, что операции чтения/записи перекрываются.

Добавление блокировки исправит результат (но вы будете эффективно сериализовать вычисление, потеряв преимущество, к которому вы стремились).

Вместо этого вы должны рассчитать промежуточный итог в каждом потоке и добавить к нему итоговые суммы. Более подробную информацию см. В статье How to: Write a Parallel.For Loop That Has Thread-Local Variables на MSDN.

long total = 0; 

// Use type parameter to make subtotal a long, not an int 
Parallel.For<long>(0, nums.Length,() => 0, (j, loop, subtotal) => 
{ 
    subtotal += nums[j]; 
    return subtotal; 
}, 
    (x) => Interlocked.Add(ref total, x) 
); 
+0

Но я думал, что Parallel.For делает все задание на синхронизацию потоков и блокирующих переменных ... –

+2

@taras: Он выполняет потоковую обработку, не делая потоки безопасными. –

+0

Но почему я должен блокировать переменную «sum», это значение типа ... –

0

Большое спасибо всем вам за ваши быстрые ответы я изменил

сумму + = я; - Interlocked.Add (ref sum, i);

и теперь он отлично работает.

+3

Это даст правильный результат, но теперь вы потеряли преимущество распараллеливания, поскольку вы эффективно сериализуете расчет. –

+2

Вы должны принять ответ выше, поскольку он вам помог! – Chad

Смежные вопросы