|
"...Изучение и анализ примеров.
В и приведены описания и приложены исходные коды параллельных программ..." Непонятно что такое - "В и приведены описания" и где именно приведены и приложены исходные коды. |
Введение в PLINQ
PLINQ (Parallel Language-Integrated Query) - параллельный интегрированный язык запросов - является параллельной реализацией LINQ. Отличие PLINQ от LINQ состоит в том, что запросы выполняются параллельно, используя, обычно, все доступные ядра/процессоры.
7.1 Использование PLINQ
PLINQ предназначен для параллельного выполнения LINQ-запросов и потому его реализация встроена в библиотеку System.Linq. PLINQ полностью поддерживает все операторы запросов, имеющиеся в .NET, и имеет минимальное влияние на существующую модель использования и исполнения LINQ-операторов.
Рассмотрим простой пример использования LINQ. Предположим, что мы имеем метод, который проверяет делимость целого числа на 5. Добавим в него некоторую длительную обработку, чтобы этот метод можно было использовать в параллельных программах:
private static bool IsDivisibleBy5 ( int p )
{
// Моделирование длительной обработки
for ( int i = 0; i < 10000000; i++ ) {
i++; i--;
}
return p % 5 == 0;
}
Пример
7.1.
Следующий фрагмент программы с использование LINQ-операторов позволяет подсчитать количество чисел в интервале от 1 до 1000, которые делятся на 5:
IEnumerable<int> arr = Enumerable.Range ( 1, 1000 );
var q =
from n in arr
where ISDivisibleBy5 ( n )
select n;
List<int> list = q.ToList();
Console.WriteLine ( list.Count.ToString() );
Пример
7.2.
Чтобы распараллелить этот запрос средствами PLINQ, достаточно применить к источнику данных (в данном случае, это перечислимый массив arr) extension-метод AsParallel():
IEnumerable<int> arr = Enumerable.Range ( 1, 1000 );
var q =
from n in arr.AsParallel()
where ISDivisibleBy5 ( n )
select n;
List<int> list = q.ToList();
Console.WriteLine ( list.Count.ToString() );
Пример
7.3.
В действительности, LINQ-запросы, записанные в SQL-подобном синтаксисе, как в Примере 2, переводятся в серию вызовов extension-методов классов, содержащихся в System.Linq.Enumerable. Другими словами, запрос из Примера 2 может быть переписан в следующей эквивалентной форме:
IEnumerable<int> q =
Enumerable.Select<int,int> (
Enumerable.Where<int> (
arr, delegate (int n) { return
IsDivisibleBy5 (n); }
),
delegate (int n) { return n; }
);
Пример
7.4.
Наряду с Enumerable, библиотека System.Linq содержит эквивалентный класс ParallelEnumerable, который содержит тот же набор методов, что и класс Enumerable, но предназначенных для параллельного исполнения.
Тогда параллельная реализация Примера 4 запишется следующим образом:
IParallelEnumerable<int> q =
ParallelEnumerable.Select<int,int> (
ParallelEnumerable.Where<int> (
ParallelQuery.AsParallel<int> (arr),
delegate (int n) { return
IsDivisibleBy5 (n); }
),
delegate (int n) { return n; }
);
Пример
7.5.
Рассмотрим еще один (схематичный) запрос, записанный в синтаксисе LINQ:
IEnumerable<T> data = …;
var q =
from x in data
where p ( x )
orderby k ( x )
select f ( x );
foreach ( var e in q )
a ( e );
Пример
7.6.
Распараллеливание исполнения этого запроса снова достигается применением extension-метода AsParallel():
IEnumerable<T> data = …;
var q =
from x in data.AsParallel()
where p ( x )
orderby k ( x )
select f ( x );
foreach ( var e in q )
a ( e );
Пример
7.7.
И снова запрос из Примера 6 может быть эквивалентно переписан с использованием Enumerable:
IEnumerable<T> data = …;
var q = Enumerable.Select(
Enumerable.OrderBy(
Enumerable.Where(data, x => p(x)),
x => k(x)),
x => f(x));
foreach (var e in q)
a(e);
Пример
7.8.
Распараллелить запрос из Примера 8 легко:
IEnumerable<T> data = …;
var q = ParallelEnumerable.Select(
ParallelEnumerable.OrderBy(
ParallelEnumerable.Where(data.AsParallel(), x => p(x)),
x => k(x)),
x => f(x));
foreach (var e in q)
a(e);
Пример
7.9.
Запрос из Примера 8 можно переписать еще одним эквивалентным способом, который отличается тем, что в нем опущены явные указания типа Enumerable, что сокращает запрос в записи, но вызывает процедуру (неявного) вывода типов на этапе компиляции программы:
IEnumerable<T> data = …; var q = data.Where(x => p(x)).Orderby(x => k(x)).Select(x => f(x)); foreach (var e in q) a(e);Пример 7.10.
Распараллеливание запроса из Примера 10 снова происходит применением метода AsParallel() к источнику данных:
IEnumerable<T> data = …;
var q = data.AsParallel().
Where(x => p(x)).Orderby(x => k(x)).Select(x => f(x));
foreach (var e in q) a(e);
Пример
7.11.