Вопрос по Курсу: "Параллельное программирование с использованием MS VisualStudia 2010". При компиляции Самостоятельного задания (одновременная отрисовка прямоугольников, эллипсов и выдача в текст-бокс случайного числа) среда предупреждает: suspend - устаревшая команда; примените monitor, mutex и т.п. Создаётся впечатление, что Задание создано в более поздней среде, чем VS 2010. |
Параллельные коллекции. Низкоуровневая синхронизация
ConcurrentQueue
В данной части практического задания, будет рассмотрен пример использования параллельной коллекции ConcurrentQueue, при разработке простого консольного приложения.
- Создадим консольное приложение и назовем его "ConcurrentQueueApplication":
- Создадим в классе Program, три статичных коллекции:
static List<int> collection1 = new List<int>(); static Queue<int> collection2 = new Queue<int>(); static ArrayList collection3 = new ArrayList();
Предварительно подключив директиву, для использования коллекции типа ArrayList:
using System.Collections
- Далее, создадим перегруженный статичный метод, который помещает значения в созданные на предыдущем шаге коллекции:
static void addNumber(int num) { try { collection1.Add(num); collection2.Enqueue(num); collection3.Add(num); } catch (AggregateException exc) { Console.WriteLine(exc); }
- В главном методе 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();
- Запустим программу. И получим следующий результат:
Примечание. Как видно из результата выполнения программы все значения были добавлены в коллекции при прохождении цикла 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(); } } }
- Теперь используем параллельный цикл Parallel.For вместо цикла for для того, что бы посмотреть, как выполняется добавление записей с использованием многопоточного цикла. Для этого, сначала, подключим директиву для использования потоков:
using System.Threading.Tasks
- Заменим цикл for на Parallel.For:
Parallel.For(0, 1000000, i => { addNumber(i); });
- Запустим программу. Программа выдаст приблизительно следующий результат:
Так же программа может вызвать исключение при добавлении элемента в одну из коллекций:
Примечание. Как видно из результатов выполнения цикла Parallel.For, не целесообразно использовать стандартные коллекции для распараллеленного кода, это приводит либо к ошибкам в ходе выполнения программы, либо к тому, что не все элементы будут помещены в коллекцию, это связанно с тем, что несколько потоков могут обращаться к одной и той же позиции коллекции при добавлении элемента.
- Теперь создадим коллекцию ConcurrentQueue. Для этого сначала подключим директиву для того, что бы использовать параллельную коллекцию:
using System.Collections.Concurrent
- Создаем коллекцию ConcurrentQueue с именем collection4:
static ConcurrentQueue<int> collection4 = new ConcurrentQueue<int>()
- Добавляем элементы в коллекцию:
collection4.Enqueue(num)
- Выводим количество элементов коллекции collection4:
Console.WriteLine("Коллекция List<int> содержит: {0} элементов \nКоллекция Queue<int> содержит: {1} элементов \nКоллекция ArrayList содержит: {2} элементов \nКоллекция ConcurrentQueue содержит: {3} элементов", collection1.Count, collection2.Count, collection3.Count,collection4.Count)
- Запустим программу. И если программа отработает безошибочно, то результат будет следующим:
Примечание. Как видно из результата выполнения программы, все элементы (от 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(); } } }