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

Cra*_*rge 6 parallel-processing .net-4.0 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]));
Run Code Online (Sandbox Code Playgroud)

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

Gab*_*abe 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;
Run Code Online (Sandbox Code Playgroud)

首先,他们都会看到_size(31)不是_items.Length(32),所以他们都执行_size++.第一个线程将获得31(第32件正常指数),并更改_size为32第二个线程将获得32并尝试指标_items[32],它给你的例外,因为它试图访问一个32个元素的数组的第33个元素.

  • 很好的答案.我希望我能两次投票.我将在我的下一篇博客文章中提到这一点; 我希望你不介意. (2认同)