2010-07-31 68 views
2

我強制性地將所有素數低於2000000的加起來。之後,爲了好玩,我試着平行我,但當我看到Parallel.For給我一個時,我有點驚訝不正確總和!.Net並行。對於奇怪的行爲

這裏是我的代碼(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) – 2010-07-31 12:14:11

+1

和確切的重複[與Parallel.ForEach不同的求和結果](http://stackoverflow.com/questions/3367293/different-summation-results-with-parallel-foreach/3367311#3367311) – 2010-07-31 13:34:20

回答

4

您正在訪問多線程中的變量總和而不鎖定它,因此讀/寫操作可能會重疊。

添加一個鎖會糾正結果(但你會有效地序列化計算,失去你所瞄準的好處)。

您應該改爲在每個線程上計算一個小計,並在最後添加小計。有關更多詳細信息,請參閱MSDN上的文章How to: Write a Parallel.For Loop That Has Thread-Local Variables

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正在做所有的同步線程和鎖定變量的作業... – 2010-07-31 12:14:21

+2

@taras:它正在執行線程,而不是使線程安全。 – 2010-07-31 12:16:14

+0

但是,爲什麼我應該鎖定變量「sum」,它是值類型的... – 2010-07-31 12:17:46

0

非常感謝大家對你的快速解答 我改變

總和+ =我; 至 Interlocked.Add(ref sum,i);

現在它工作得很好。

+3

它會給出正確的結果,但現在您已經失去了並行化的好處,因爲您正在有效地序列化計算。 – 2010-07-31 13:30:17

+2

你應該接受上面的答案,因爲它可以幫助你! – Chad 2010-07-31 13:44:48