Console.WriteLine("Основной поток запущен."); data = new int[100000000];
// Инициализировать данные.
for (int i=0; i < data.Length; i++) data[i] = i;
// Поместить отрицательное значение в массив data, data[100000] = -10;
// Использовать цикл, параллельно выполняемый методом ForEachO,
// для отображения данных на экране.
ParallelLoopResult loopResult = Parallel.ForEach(data, DisplayData);
// Проверить, завершился ли цикл, if(!loopResult.IsCompleted)
Console.WriteLine("ХпЦикл завершился преждевременно из-за того, " +
"что обнаружено отрицательное значение\п" +
"на шаге цикла номер " +
loopResult.LowestBreaklteration + ".\n");
Console.WriteLine("Основной поток завершен.");
}
}
В приведенной выше программе именованный метод применяется в качестве делегата, представляющего "тело" цикла. Но иногда удобнее применять анонимный метод. В качестве примера ниже приведено реализуемое в виде лямбда-выражения "тело" цикла, параллельно выполняемого методом ForEach ().
// Использовать цикл, параллельно выполняемый методом ForEachO,
// для отображения данных на экране.
ParallelLoopResult loopResult =
Parallel.ForEach(data, (v, pis) => {
Console.WriteLine("Значение: " + v); if (v < 0) pis.Break ();
});
Исследование возможностей PLINQ
PLINQ представляет собой параллельный вариант языка интегрированных запросов LINQ и тесно связан с библиотекой TPL. PLINQ применяется, главным образом, для достижения параллелизма данных внутри запроса. Как станет ясно из дальнейшего, сделать это совсем не трудно. Как и TPL, тема PLINQ довольно обширна и многогранна, поэтому в этой главе представлены лишь самые основные понятия данного языка.
Класс ParallelEnumerable
Основу PLINQ составляет класс ParallelEnumerable, определенный в пространстве имен System. Linq. Это статический класс, в котором определены многие методы расширения, поддерживающие параллельное выполнение операций. По существу, он представляет собой параллельный вариант стандартного для LINQ класса Enumerable. Многие его методы являются расширением класса ParallelQuery, а некоторые из них возвращают объект типа ParallelQuery. В классе ParallelQuery инкапсулируется последовательность операций, поддерживающая параллельное выполнение. Имеются как обобщенный, так и необобщенный варианты данного класса. Мы не будем обращаться к классу ParallelQuery непосредственно, а воспользуемся несколькими методами класса ParallelEnumerable. Самый главный из них, метод As Parallel (), описывается в следующем разделе.
Распараллеливание запроса методом AsParallel ()
Едва ли не самым удобным средством PLINQ является возможность просто создавать параллельный запрос. Нужно лишь вызвать метод AsParallel () для источника данных. Метод AsParallel () определен в классе ParallelEnumerable и возвращает источник данных, инкапсулированный в экземпляре объекта типа ParallelQuery. Это дает возможность поддерживать методы расширения параллельных запросов. После вызова данного метода запрос разделяет источник данных на части и оперирует с каждой из них таким образом, чтобы извлечь максимальную выгоду из распараллеливания. (Если распараллеливание оказывается невозможным или неприемлемым, то запрос, как обычно, выполняется последовательно.) Таким образом, добавления в исходный код единственного вызова метода AsParallel () оказывается достаточно для того, чтобы превратить последовательный запрос LINQ в параллельный запрос LINQ. Для простых запросов это единственное необходимое условие.
Существуют как обобщенные, так и необобщенные формы метода AsParallel (). Ниже приведена простейшая обобщенная его форма:
public static ParallelQuery AsParallel(this IEnumerable source) public static ParallelQuery<TSource>
AsParallel<TSource>(this IEnumerable<TSource> source)
где TSource обозначает тип элементов в последовательном источнике данных
source.
Ниже приведен пример, демонстрирующий простой запрос PLINQ.
// Простой запрос PLINQ.
using System; using System.Linq;
class PLINQDemo {
static void Main() {
int[] data = new int[10000000];
I
// Инициализировать массив данных положительными значениями, for(int i=0; i < data.Length; i++) data[i] = i;
//А теперь ввести в массив данных ряд отрицательных значений