使用Parallel for循环时索引超出范围异常

时间:2010-10-24 04:51:05

标签: .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.For(0, array.Length, i => list.Add(array[i]));

我在这里做错了吗?我理解这个过程是无序的/异步的,但为什么“i”得到的值高于“array.Length”的值?

1 个答案:

答案 0 :(得分:18)

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

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

现在假设您的列表最多包含31个元素(意味着它有一个空格),两个线程尝试添加第32个元素。他们都会执行这样的代码:

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

首先,他们都会看到_size(31)不是_items.Length(32),所以他们都执行_size++。第一个线程将获得31(第32个元素的正确索引)并将_size更改为32.第二个线程将获得32并尝试索引_items[32],这会为您提供异常,因为它正在尝试访问32元素数组的第33个元素。