【问题标题】:Index out of range exception when using Parallel for loop使用并行 for 循环时索引超出范围异常
【发布时间】:2010-11-21 22:01:22
【问题描述】:

我正在尝试执行以下代码,但在尝试将数组值分配给列表时,我不断收到 Index out of range 异常:-

        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”的值?

【问题讨论】:

    标签: .net-4.0 parallel-processing task-parallel-library


    【解决方案1】:

    问题是你不能在多个线程上同时调用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],这会给您异常,因为它正在尝试访问第 33 个元素一个 32 元素的数组。

    【讨论】:

    • 优秀的答案。我希望我可以投票两次。我将在下一篇博客文章中引用它;希望你不要介意。
    猜你喜欢
    • 2013-09-28
    • 2019-04-17
    • 2013-11-25
    • 2017-08-09
    • 1970-01-01
    • 1970-01-01
    • 2013-08-16
    • 1970-01-01
    • 2021-09-02
    相关资源
    最近更新 更多