2012-10-06 20 views
0

我做了這個小程序來測試並行化。爲什麼C#的Parallel.ForEach拋出IndexOutOfBounds和foreach不?

當我多次敲擊button1時,它以IndexOutOfBounds異常結束。我想這是因爲我內存不足。爲什麼我要使用並行化而不是常規的foreach(按鈕2單擊)?

private void button1_Click(object sender, EventArgs e) 
{ 
    var s = Stopwatch.StartNew(); 

    int[] nums = new int[10000]; 
    List<int> randoms = new List<int>(); 

    Parallel.ForEach(nums, i => 
    { 
     randoms.Add(new Random().Next()); 
    }); 

    s.Stop(); 
    label1.Text = "Added " + randoms.Count() + " randoms in " 
        + s.Elapsed.Milliseconds.ToString() + " milliseconds"; 
} 

private void button2_Click(object sender, EventArgs e) 
{ 
    var s = Stopwatch.StartNew(); 

    int[] nums = new int[10000]; 
    List<int> randoms = new List<int>(); 
    foreach (var i in nums) 
    { 
     randoms.Add(new Random().Next()); 
    } 

    s.Stop(); 
    label2.Text = "Added " + randoms.Count() + " randoms in " 
        + s.Elapsed.Milliseconds.ToString() + " milliseconds"; 
} 

回答

2

您並行修改randoms。這是一個錯誤,因爲該列表對於併發添加不安全。

此外,IndexOutOfBounds與內存不足無關。您可以通過仔細查看例外情況來了解所有這些信息:消息告訴您這不是OOM。堆棧跟蹤告訴你在哪一行發生了錯誤(這是在Add-行,對吧?)。

+0

我明白了。所以我不能添加到並行列表中?有沒有其他方法可以做到這一點?你是對的例外。我不知道爲什麼我錯過了那個。 – espvar

+0

@espvar你可以使用鎖。這會引發瘋狂的爭論,破壞所有的好處。研究PLINQ - 這對於創造價值是有益的。 (你也需要解決併發隨機數的問題,它有陷阱 - 谷歌它)。 – usr

2

在你Parallel.ForEach代碼,你同時修改List<int>這不是線程安全的。

當您試圖在List的末尾添加內存數組並在另一個線程中調整大小時,會發生異常。

相反,你應該使用併發收集像ConcurrentBagConcurrentQueue

+0

謝謝。這實際上讓我更瞭解更多並行工作與單線程不同的地方。 – espvar

相關問題