Вопрос по Курсу: "Параллельное программирование с использованием MS VisualStudia 2010". При компиляции Самостоятельного задания (одновременная отрисовка прямоугольников, эллипсов и выдача в текст-бокс случайного числа) среда предупреждает: suspend - устаревшая команда; примените monitor, mutex и т.п. Создаётся впечатление, что Задание создано в более поздней среде, чем VS 2010. |
Параллелизм данных
Класс Parallel
Одним из новых классов в .NET Framework 4.0 - является класс System.Threading.Tasks.Parallel. Этот класс поддерживает набор методов, которые позволяют выполнять итерации по коллекции данных в параллельном режиме. Одними из таких методов являются Parallel.For() и Parallel.ForEach(), Parallel.Invoke():
- Parallel.Invoke: выполняет параллельно массив делегатов;
- Parallel.For: параллельный эквивалент цикла for;
- Parallel.ForEach: параллельный эквивалент цикла foreach.
Все три метода блокируют управление до окончания выполнения всех действий. При возникновении необработанного исключения, в каком-то из потоков, оставшиеся рабочие потоки прекращают выполнение, и вызывается исключение - AggregationException. Основные методы класса Parallel представлены в Табл. 9.1.
Имя | Описание |
---|---|
For(Int32, Int32, Action) | Выполняет цикл for, в котором итерации могут выполняться параллельно. |
For(Int32, Int32, Action<Int32,ParallelLoopState>) | Выполняет цикл for, обеспечивая возможность параллельного выполнения итераций, а также контроля состояния цикла и управления этим состоянием. |
ForEach(IEnumerable, Action) | Выполняет операцию foreach (For Each в Visual Basic) для объекта IEnumerable, обеспечивая возможность параллельного выполнения итераций. |
ForEach(IEnumerable, Action<Int32,ParallelLoopState>) | Выполняет операцию foreach (For Each в Visual Basic) для объекта IEnumerable, обеспечивая возможность параллельного выполнения итераций, а также контроля состояния цикла и управления этим состоянием. |
Invoke(Action[]) | Выполняет все предоставленные действия, в том числе параллельно. |
Invoke(ParallelOptions, Action[]) | Выполняет каждое из указанных действий по возможности в параллельном режиме, если операция не отменена пользователем. |
Parallel.Invoke
Метод Parallel.Invoke() позволяет выполнять один или несколько методов, указываемых в виде его аргументов. При использовании данного метода отпадает необходимость использования метода Wait(), т.к. Invoke() сначала инициирует выполнение, а затем ожидает завершения всех передаваемых ему методов. Простая версия этого метода описана ниже:
public static void Invoke (params Action[] actions);
Существует также перегруженная версия метода Parallel.Invoke(), которая принимает объект класса ParallelOptions:
public static void Invoke (ParallelOptions options, params Action[] actions);
где optinons - объект класса ParallelOptions, с помощью которого можно добавлять маркеры (token) отмены, ограничить максимальное количество рабочих потоков или указать свой планировщик задач (custom task scheduler). Использование маркеров отмены полезно, когда число одновременно выполняемых задач превосходит количество ядер процессора: при отмене все делегаты, выполнение которых еще не было начато, будут отменены. Однако все делегаты, выполнение которых уже начато, продолжат до завершения.
Пример работы метода Invoke() представлен ниже:
static void Hello() { Console.WriteLine("Hello"); } static void World() { Console.WriteLine("World!"); } static void WorldHello() { Console.WriteLine("World Hello!"); } static void Main(string[] args) { Parallel.Invoke(Hello, World, WorldHello); Console.ReadLine(); }
Parallel.For
Метод Parallel.For() аналогичен оператору for, за исключением того что все итерации выполняются в отдельных потоках, при этом порядок выполнения итераций не определен. Конструкция данного метода представлена ниже:
Parallel.For (Int32, Int32, Action)
где первый параметр (Int32) - начальный индекс (включительно) цикла, второй параметр (Int32) - это конечный индекс (не включительно) цикла, третий параметр (Action) передаётся делегат, который вызывается один раз за итерацию. Возвращаемым типом у метода Parallel.For() является структура ParallelLoopResult, в которой содержатся сведения о выполненной части цикла.
Пример использование параллельного цикла Parallel.For() представлен ниже:
Parallel.For(0, 10, i => { Console.WriteLine("{0}, Задача: {1}, Поток: {2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); }); Console.ReadLine();
В одной из перегрузок этого метода Parallel.For() есть третий параметр Action<int, ParallelLoopState>. С помощью такой перегрузки метода, можно оказывать влияние на выполнение цикла с помощью методов Break() и Stop() объекта ParallelLoopState:
- Stop() - применяется в алгоритмах поиска, где после нахождения результата, выполнять другие итерации не требуется;
- Break() - используется для передачи циклу информации, что другие итерации после текущей итерации выполнять не требуется.
Пример кода с использованием объекта ParallelLoopState представлен ниже:
Parallel.For(0, 100, (i,state) => { Console.WriteLine("{0}, Задача: {1}, Поток: {2}", i, Task.CurrentId, Thread.CurrentThread.ManagedThreadId); Thread.Sleep(10); if (i == 55) state.Break(); });
увеличить изображение
Рис. 9.3. Результат работы программы с использованием метода Parallel.For() и объекта ParallelLoopState