Параллель Для Цикла - проблемы при добавлении к Списку

У меня есть некоторые проблемы, включающие Параллель для циклов и добавляющие к Списку. Проблема, тот же код может генерировать другой вывод в разное время. Я настроил некоторый тестовый код ниже. В этом коде я создаю Список 10 000 международных значений. 1/10-й из значений будет 0, 1/10-й из значений будет 1, полностью до 1/10-го из значений, являющихся 9.

После установки этого Списка я устанавливаю Параллель для цикла, который выполняет итерации через список. Если текущее число 0, я добавляю значение к новому Списку. После того, как Параллель для цикла завершается, я произвел размер списка. Размер должен всегда быть 1,000. Большую часть времени корректный ответ дан. Однако я видел, что происходят 3 возможных неправильных результата:

  1. Размер списка - меньше чем 1 000
  2. IndexOutOfRangeException происходит doubleList.Add(0.0);
  3. ArgumentException происходит doubleList.Add(0.0);

Сообщение для данного ArgumentException было: Destination array was not long enough. Check destIndex and length, and the array's lower bounds.

Что могло вызывать ошибки? Действительно ли это - ошибка .NET? Есть ли что-то, что я могу сделать для предотвращения этого?

Попробуйте код за себя. Если Вы не получаете ошибку, попробуйте ее несколько раз. Также обратите внимание, что Вы, вероятно, не будете видеть ошибок использовать одножильную машину.

using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ParallelTest
{
    class Program
    {
        static void Main(string[] args)
        {
            List intList = new List();
            List doubleList = new List();

            for (int i = 0; i < 250; i++)
            {
                intList.Clear();
                doubleList.Clear();

                for (int j = 0; j < 10000; j++)
                {
                    intList.Add(j % 10);
                }

                Parallel.For(0, intList.Count, j =>
                {
                    if (intList[j] == 0)
                    {
                        doubleList.Add(0.0);
                    }
                });

                if (doubleList.Count != 1000)
                {
                    Console.WriteLine("On iteration " + i + ": List size = " + doubleList.Count);
                }
            }

            Console.WriteLine("\nPress any key to exit.");
            Console.ReadKey();
        }
    }
}

6
задан Kevin Crowell 2 May 2010 в 04:03
поделиться

1 ответ

Я ожидаю, что System.Collections.Generic.List не является потокобезопасным, что означает, что если вы попытаетесь одновременно Добавить из двух разных потоков, все пойдет не так. Ах да, так сказано в документах .

Вы можете предотвратить это несколькими способами:

  • используйте тип коллекции, который позволяет добавлять потокобезопасные (есть несколько новых в .Net 4.0)
  • заблокируйте перед добавлением
  • используют локальное хранилище потока для коллекций и объединяют их в конце
  • ...

Это очень типичные проблемы, с которыми вы сталкиваетесь при работе с параллельным кодом данных.

19
ответ дан 8 December 2019 в 12:18
поделиться
Другие вопросы по тегам:

Похожие вопросы: