Why does C# Parallel.ForEach throw IndexOutOfBound

2019-08-24 09:50发布

I made this small program to test parallelization.

When I hit button1 several times it ends up with an IndexOutOfBounds exception. I guess this is because I run out of memory. Why do I get this with parallelization and not with a regular foreach(button2 click)?

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条回答
再贱就再见
2楼-- · 2019-08-24 10:07

In your Parallel.ForEach code, you are concurrently modifying a List<int> which is not threadsafe.

The exception occurs when you try to add to the end of a List while the internal array is being resized in a different thread.

Instead you should use a concurrent collection like ConcurrentBag or ConcurrentQueue

查看更多
欢心
3楼-- · 2019-08-24 10:28

You are modifying randoms in parallel. That is a bug because the list is not safe for concurrent adding.

Also, IndexOutOfBounds has nothing to do with out-of-memory. You can find out all of this by looking carefully at the exception: The message tells you it is not OOM. And the stack trace tells you in which line the error occured (it was in the Add-line, right?).

查看更多
登录 后发表回答