.net 4.0 使用并行for循环时索引超出范围异常

.net 4.0 使用并行for循环时索引超出范围异常,.net-4.0,parallel-processing,task-parallel-library,.net 4.0,Parallel Processing,Task Parallel Library,我正在尝试执行以下代码,在尝试将数组值分配给列表时,我不断获得索引超出范围的异常:- int[] array = new int[1000000]; for (int i = 0; i < array.Length; i++) { array[i] = i; } List<int> list = new List<int>(); Parallel

我正在尝试执行以下代码,在尝试将数组值分配给列表时,我不断获得索引超出范围的异常:-

        int[] array = new int[1000000];
        for (int i = 0; i < array.Length; i++)
        {
            array[i] = i;
        }

        List<int> list = new List<int>();
        Parallel.For(0, array.Length, i => list.Add(array[i]));
int[]数组=新的int[1000000];
for(int i=0;ilist.Add(array[i]));

我做错什么了吗?我知道该进程是无序/异步的,但是为什么“I”得到的值高于“array.Length”的值呢?

问题是,您不能在多个线程上同时调用
List.Add()
。如果需要线程安全集合,请参阅
System.collections.Concurrent
命名空间

如果在出现异常时闯入调试器,您将看到
i
不大于
array.Length
,而是大大小于
array.Length
的2的幂。发生的情况是,
列表
以一个类似4个元素的空数组开始。每当向数组已满的列表中添加元素时,它都会创建一个长度为旧数组两倍的数组,将旧元素复制到该数组中,并存储新数组

现在让我们假设您的列表最多有31个元素(这意味着它还有一个元素的空间),两个线程尝试添加第32个元素。它们都将执行如下代码:

if (_size == _items.Length)
{
    EnsureCapacity(_size + 1);
}
_items[_size++] = item;

首先,它们都会看到
\u size
(31)不是
\u items.Length
(32),因此它们都执行
\u size++
。第一个线程将得到31(第32个元素的正确索引),并将
\u size
更改为32。第二个线程将得到32,并尝试索引
\u items[32]
,这会给您一个异常,因为它试图访问32元素数组的第33个元素。

回答得很好。我希望我能投两次赞成票。我将在下一篇博文中引用这一点;我希望你不介意。