Parallel Extensions: параллельный взгляд на вещи
Вступление
C каждым днем жизнь программиста усложняется, так как приходится следить и изучать новые технологии, фреймворки и т.д. Но вместе с тем большая часть рутинных задач упрощается. Примером такого упрощения является Microsoft Parallel Extensions to .NET Framework 3.5, June 2008 Community Technology Preview, который можно Источник В Parallel Extensions реализовано несколько подходов
Деклартивный параллелизм (Declarative data parallelism) - Parallel Language Integrated Query (или Parallel LINQ, сокращенно PLINQ) - это реализация LINQ-to-Objects, который исполняет запросы параллельно, используя доступные ядра и процессоры машины.
Императивный параллелизм (Imperative data parallelism) - Parallel Extensions также содержат механизмы выполнения императивных операций, таких как for и foreach, параллельно, автоматически разделяя выполнение цикла.
Императивное распараллеливание задач (Imperative task parallelism) - возможность запускать несколько задач параллельно, а также отменять и ждать конкретные задачи.
Требования: наличие установленного .NET Framework 3.5.
Task Parallel Library
Последовательная модель, реализованная в System.Threading.Tasks.Task и System.Threading.Tasks.Future классах, позволяет с помощью метода ContinueWith запускать некое задание после окончания предыдущих, таким образом модно управлять расписанием задач и приоритетом их выполнения.
Особенно это актуально для Future, где есть доступ до значения Value предыдущей задачи, что дает возможность писать dataflow-oriented приложения:
var futureC = Future.Create(() => A()).ContinueWith(a => B(a.Value)) .ContinueWith(b => C(b.Value));
Следующим интересным моментом является метод WaitAny, который ждет окончание работы любого из заданных методов. Рассмотрим пример:
var algorithms = new [] { Future.Create(() => Alg1()) , Future.Create(() => Alg2()) , Future.Create(() => Alg3()) , Future.Create(() => Alg4()) }; var result = algorithms[Task.WaitAny(algorithms)].Value;
В данном случае результат получим тогда, когда любой из алгоритмов Alg1, Alg2, Alg3, Alg4 закончит свою работу. PLINQ - AsParallel()
Помните, в КВНе: наличие баяна на сцене автоматически делает наше выступление музыкальным [:)]! Так и здесь: наличие выражения AsParallel() в LINQ-запросe автоматически делает его параллельным:
IEnumerable list = new int[] { 1, 2, 3, 4, 5, 6, 7, 9, 10 }; var result = list.Where(i => (i > 5)).Count(); IEnumerable list = new int[] { 1, 2, 3, 4, 5, 6, 7, 9, 10 }; var result = list.AsParallel().Where(i => (i > 5)).Count(); Parallel.For и Parallel.FoEach
Как вы уже догадались, Parallel.For и Parallel.ForEach дают возможность выполнять циклы For и ForEach параллельно.
Для этого код
for (int i = start; i < end; i++) DoSomeWork();
нужно переписать в виде:
Parallel.For(start, end, i=> DoSomeWork());
Даже можно записывать результаты выполнения функции
for (int i = 0; i < N; i++) { results[i] = Compute(i); }
как:
Parallel.For(0, N, delegate(int i) { results[i] = Compute(i); } );
C ForEach нужно быть осторожнее, так как синхронизацию нужно реализовывать самому. Parallel.Invoke()
Parallel.Invoke() используется для выполнения разноплановых задач, как правило, не связанных между собой. Пример использования:
static void WalkTree(Tree tree, Action func) { if (tree == null) return; WalkTree(tree.Left, func); WalkTree(tree.Right, func); func(tree.Data); }
Переписываем как:
static void WalkTree(Tree tree, Action func) { if (tree == null) return; Parallel.Invoke( () => WalkTree(tree.Left, func) , () => WalkTree(tree.Right, func) , () => func(tree.Data) ); }
Таким образом, используя Parallel Extensions, мы имеем возможность с минимальными изменениями кода получить более производительный код. Но о производительности и некоторых других возможностях библиотеки поговорим в следующий раз.
Компании из статьи
Microsoft Украина | Украинское подразделение компании Microsoft. |