Индекс вне диапазона Исключение при использовании параллельного для петли

StackOverflow https://stackoverflow.com/questions/4007248

Вопрос

Я пытаюсь выполнить следующий код, и я продолжаю получать индекс из исключения диапазона при попытке назначить значения массива в список: -

        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]));

Я здесь делаю что-то не так? Я понимаю, что процесс неупорядован / асинхронный, но почему «я» получаю значения, которые выше, чем значение «Array.Length»?

Это было полезно?

Решение

Проблема в том, что вы не можете позвонить 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-элементного массива.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top