Опубликован: 23.01.2013 | Уровень: для всех | Доступ: платный | ВУЗ: Томский политехнический университет
Лекция 11:

Параллельные коллекции. Низкоуровневая синхронизация

ConcurrentQueue

В данной части практического задания, будет рассмотрен пример использования параллельной коллекции ConcurrentQueue, при разработке простого консольного приложения.

  1. Создадим консольное приложение и назовем его "ConcurrentQueueApplication":
  2. Создадим в классе Program, три статичных коллекции:
    static List<int> collection1 = new List<int>();
           static Queue<int> collection2 = new Queue<int>();
           static ArrayList collection3 = new ArrayList();

    Предварительно подключив директиву, для использования коллекции типа ArrayList:

    using System.Collections
  3. Далее, создадим перегруженный статичный метод, который помещает значения в созданные на предыдущем шаге коллекции:
    static void addNumber(int num)
        {
            try
            {
                collection1.Add(num);
                collection2.Enqueue(num);
                collection3.Add(num);
            
            }
            catch (AggregateException exc)
            {
                Console.WriteLine(exc);
            }
  4. В главном методе Main, реализуем наполнение коллекций через цикл for с использованием метода addNumber:
    for (int i = 0; i < 1000000; i++)
         {
             addNumber(i);
         }
         Console.WriteLine("Коллекция List<int> содержит: 
    {0} элементов \nКоллекция Queue<int> содержит: {1} элементов \nКоллекция ArrayList содержит: 
    {2} элементов", collection1.Count, collection2.Count, collection3.Count);
         Console.ReadLine();
  5. Запустим программу. И получим следующий результат:

    Примечание. Как видно из результата выполнения программы все значения были добавлены в коллекции при прохождении цикла for.

    Листинг кода программы:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using System.Threading.Tasks;
    namespace ConcurrentQueueApplication
    {
        class Program
        {
           static List<int> collection1 = new List<int>();
           static Queue<int> collection2 = new Queue<int>();
           static ArrayList collection3 = new ArrayList();
           static void addNumber(int num)
            {
                try
                {
                    collection1.Add(num);
                    collection2.Enqueue(num);
                    collection3.Add(num);
                 }
                 catch (Exception exc)
                {
                    Console.WriteLine(exc);
                }
            }
            static void Main(string[] args)
            {
                for (int i = 0; i < 1000000; i++)
                {
                    addNumber(i);
                }
                Console.WriteLine("Коллекция List<int> содержит: 
      {0} элементов \nКоллекция Queue<int> содержит: 
       {1} элементов \nКоллекция ArrayList содержит: {2} элементов", 
        collection1.Count, collection2.Count, collection3.Count);
                Console.ReadLine();
            }
        }
    }
  6. Теперь используем параллельный цикл Parallel.For вместо цикла for для того, что бы посмотреть, как выполняется добавление записей с использованием многопоточного цикла. Для этого, сначала, подключим директиву для использования потоков:
    using System.Threading.Tasks
  7. Заменим цикл for на Parallel.For:
    Parallel.For(0, 1000000, i =>
                {
                    addNumber(i);
                });
  8. Запустим программу. Программа выдаст приблизительно следующий результат:

    Так же программа может вызвать исключение при добавлении элемента в одну из коллекций:

    Примечание. Как видно из результатов выполнения цикла Parallel.For, не целесообразно использовать стандартные коллекции для распараллеленного кода, это приводит либо к ошибкам в ходе выполнения программы, либо к тому, что не все элементы будут помещены в коллекцию, это связанно с тем, что несколько потоков могут обращаться к одной и той же позиции коллекции при добавлении элемента.

  9. Теперь создадим коллекцию ConcurrentQueue. Для этого сначала подключим директиву для того, что бы использовать параллельную коллекцию:
    using System.Collections.Concurrent
  10. Создаем коллекцию ConcurrentQueue с именем collection4:
    static ConcurrentQueue<int> collection4 = new ConcurrentQueue<int>()
  11. Добавляем элементы в коллекцию:
    collection4.Enqueue(num)
  12. Выводим количество элементов коллекции collection4:
    Console.WriteLine("Коллекция List<int> содержит: 
    {0} элементов \nКоллекция Queue<int> содержит: 
    {1} элементов \nКоллекция ArrayList содержит: 
    {2} элементов \nКоллекция ConcurrentQueue содержит: 
    {3} элементов", collection1.Count, collection2.Count, collection3.Count,collection4.Count)
  13. Запустим программу. И если программа отработает безошибочно, то результат будет следующим:

    Примечание. Как видно из результата выполнения программы, все элементы (от 0 до 1000000) будут помещены в коллекцию ConcurrentQueue.

    Листинг кода программы:

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Collections;
    using System.Threading.Tasks;
    using System.Collections.Concurrent;
    namespace ConcurrentQueueApplication
    {
        class Program
        {
           static List<int> collection1 = new List<int>();
           static Queue<int> collection2 = new Queue<int>();
           static ArrayList collection3 = new ArrayList();
           static ConcurrentQueue<int> collection4 = new ConcurrentQueue<int>();
           static void addNumber(int num)
            {
                try
                {
                    collection1.Add(num);
                    collection2.Enqueue(num);
                    collection3.Add(num);
                    collection4.Enqueue(num);
                }
                catch (Exception exc)
                {
                    Console.WriteLine(exc);
                }
            }
            static void Main(string[] args)
            {
          
                Parallel.For(0, 1000000, i =>
                {
                    addNumber(i);
                });
                Console.WriteLine("Коллекция List<int> содержит: 
      {0} элементов \nКоллекция Queue<int> содержит: 
      {1} элементов \nКоллекция ArrayList содержит: {2} элементов \nКоллекция ConcurrentQueue содержит:
          {3} элементов", collection1.Count, collection2.Count, collection3.Count,collection4.Count);
               Console.ReadLine();
            }
        }
    }
Владимир Каширин
Владимир Каширин

Вопрос по Курсу: "Параллельное программирование с использованием MS VisualStudia 2010".

При компиляции Самостоятельного задания (одновременная отрисовка прямоугольников, эллипсов и выдача в текст-бокс случайного числа) среда предупреждает: suspend - устаревшая команда; примените monitor, mutex и т.п.

Создаётся впечатление, что Задание создано в более поздней среде, чем VS 2010.

Александр Гаврилов
Александр Гаврилов
Россия
Роман Дмитриев
Роман Дмитриев
Россия, Москва