为什么C#Parallel.ForEach抛出IndexOutOfBounds而ForEach不抛出IndexOutOfBounds?

为什么C#Parallel.ForEach抛出IndexOutOfBounds而ForEach不抛出IndexOutOfBounds?,c#,parallel-processing,C#,Parallel Processing,我制作了这个小程序来测试并行化 当我多次按下按钮1时,它会以IndexOutOfBounds异常结束。我想这是因为我的内存不足。为什么我要通过并行化而不是常规的foreach(按钮2点击)来实现这一点 private void按钮1\u单击(对象发送者,事件参数e) { var s=Stopwatch.StartNew(); int[]nums=新int[10000]; 列表随机数=新列表(); Parallel.ForEach(nums,i=> { 添加(new Random().Next()

我制作了这个小程序来测试并行化

当我多次按下按钮1时,它会以IndexOutOfBounds异常结束。我想这是因为我的内存不足。为什么我要通过并行化而不是常规的foreach(按钮2点击)来实现这一点

private void按钮1\u单击(对象发送者,事件参数e)
{
var s=Stopwatch.StartNew();
int[]nums=新int[10000];
列表随机数=新列表();
Parallel.ForEach(nums,i=>
{
添加(new Random().Next());
});
s、 停止();
label1.Text=“添加”+randoms.Count()+“随机数输入”
+ToString()+“毫秒”;
}
私有无效按钮2\u单击(对象发送者,事件参数e)
{
var s=Stopwatch.StartNew();
int[]nums=新int[10000];
列表随机数=新列表();
foreach(以nums为单位的var i)
{
添加(new Random().Next());
}
s、 停止();
label2.Text=“添加了”+randoms.Count()+“随机数输入”
+ToString()+“毫秒”;
}

在您的
并行中。对于每个
代码,您同时修改的
列表
不是线程安全的

当在不同线程中调整内部数组的大小时,尝试添加到
列表的末尾时,会发生异常


相反,您应该在
并行中使用类似或的并发集合。对于每个
代码,您同时修改的
列表是非线程安全的

当在不同线程中调整内部数组的大小时,尝试添加到
列表的末尾时,会发生异常


相反,您应该使用一个并发集合,如或,您正在并行修改随机数。这是一个bug,因为列表对于并发添加来说是不安全的


此外,IndexOutOfBounds与内存不足无关。您可以通过仔细查看异常来发现所有这些:消息告诉您它不是OOM。堆栈跟踪告诉您错误发生在哪一行(它在
Add
-行,对吗?)

您正在并行修改
randoms
。这是一个bug,因为列表对于并发添加来说是不安全的


此外,IndexOutOfBounds与内存不足无关。您可以通过仔细查看异常来发现所有这些:消息告诉您它不是OOM。堆栈跟踪告诉您错误发生在哪一行(它在
Add
-行,对吧?)。

我明白了。所以我不能在并行列表中添加?还有别的办法吗?关于例外情况,你是对的。我不知道为什么我读错了。@espvar你可以用一把锁。不过,这会引发疯狂的争论,破坏所有利益。看看PLINQ——它有助于创造价值。(您还需要解决并行随机数生成的问题,这其中有陷阱-谷歌it)。我明白了。所以我不能在并行列表中添加?还有别的办法吗?关于例外情况,你是对的。我不知道为什么我读错了。@espvar你可以用一把锁。不过,这会引发疯狂的争论,破坏所有利益。看看PLINQ——它有助于创造价值。(您还需要解决并行随机数生成的问题,这其中有陷阱-谷歌it)。谢谢。这实际上让我更了解了muuch并行与单线程的不同之处。谢谢。这实际上让我更了解了muuch,并行与单线程的工作方式有什么不同。
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";
}