Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Многопоточность.docx
Скачиваний:
0
Добавлен:
01.04.2025
Размер:
113 Кб
Скачать
☆

Класс Parallel

Прежде всего, в .NET Framework 4.0 появился класс Parallel, который имеет методы For, ForEach и Invoke. Как несложно понять, первые два из них занимаются тем, что исполняют некоторый метод в цикле (класс Exercise1). Первому из них передаются границы цикла, а второму – коллекция:

Parallel.For((long)(1000000021 - 20), (long)(1000000021 + 20), CheckParameterPrimeNumber);

От обычных циклов for и foreach эти методы отличаются только тем, что выполняют тело цикла в отдельном потоке для каждой из итераций цикла.

Следует так же отметить, что хотя каждая итерация выполняется в отдельном потоке, вызов этих методов не вернет управление пока все итерации не завершатся. Это логично, т.к. нет никаких иных механизмов ожидания завершения всех потоков.

Таким образом, данные методы просто позволяют вам лучше использовать ресурсы системы (например, несколько процессоров).

Метод Invoke в качестве параметра принимает коллекцию делегатов, каждый из которых он выполнит в отдельном потоке (класс Exercise2):

Parallel.Invoke(

() => CheckParameterPrimeNumber(1000000020),

() => CheckParameterPrimeNumber(1000000021),

() => CheckParameterPrimeNumber(1000000022),

() => CheckParameterPrimeNumber(1000000023)

);

Этот метод так же вернет управление только после завершения выполнения всех своих делегатов.

Метод AsParallel()

Кроме указанного класса Parallel Microsoft добавил похожую поддержку многопоточности в LINQ. Осуществляется она с помощью метода AsPartallel (класс Exercise3). Предположим, что нам нужно найти все простые числа из некоторого списка. Ранее мы могли бы сделать это так:

var primes = from v in values where IsPrime(v) select v;

Теперь, когда мы захотели бы перечислить все простые числа в цикле foreach, наш метод IsPrime последовательно вызывался бы для каждого из чисел списка values.

Теперь же мы можем заставить систему параллельно проверять несколько чисел сразу:

var primes = from v in values.AsParallel() where IsPrime(v) select v;

Все, что для этого нужно, добавить вызов метода AsParallel. Как видите, добавление многопоточности к обработке коллекций – довольно простое дело. Однако, конечно же, при этом необходимо, чтобы элементы коллекции действительно могли обрабатываться независимо друг от друга. Задача программиста – убедиться в этом.

Синхронизация потоков

В реальном приложении потоки часто используют совместные ресурсы. Это означает, в частности, что несколько потоков сразу могут обращаться и изменять одну и ту же переменную. Зачастую это может приводить к нежелательным последствиям. Рассмотрим следующий пример. Есть 3 потока. Первый из них добавляет элементы в некоторый список. Остальные 2 потока удаляют элементы из этого списка. Чтобы удаление произошло правильно, необходимо, чтобы в списке был хотя бы один элемент. Поэтому удаляющие потоки используют следующий код:

if (list.Count > 0)

list.RemoveAt(0);

Пусть в некоторый момент времени в списке находится единственный элемент. Вполне возможен следующий вариант работы удаляющих потоков:

Квант времени

Удаляющий поток 1

Результат работы потока 1

Удаляющий поток 2

Результат работы потока 2

1

if (list.Count > 0)

true

2

if (list.Count > 0)

true

3

list.RemoveAt(0);

Ok

4

list.RemoveAt(0);

Exception

Поэтому существует необходимость синхронизировать (упорядочивать) работу потоков, использующих одни и те же данные. Здесь мы рассмотрим механизмы, существующие для этого в .NET Framework (проект Synchronization).