Опубликован: 22.04.2008 | Уровень: профессионал | Доступ: платный
Дополнительный материал 16:

Разработка сложных параллельных программ на языке MC#

Цель - изучить параллельный алгоритм вычисления частичных сумм массива чисел и реализовать его на языке MC#.

На данном занятии, требуется реализовать программу на языке MC#, решающую задачу вычисления частичных сумм массива f длины n.

А именно, по заданному массиву чисел f [ 0 : n-1 ] необходимо построить массив h [ 0 : n-1 ], такой что

h[j]=\sum\limit_{i=0}^j f[i]\quad,\quad\mbox{для каждого }j:\; 0\le j<n

Идея параллельного решения этой задачи состоит в разбиении массива f на p сегментов, где n кратно p, с дальнейшей одновременной обработкой этих сегментов данных длины m = n div p. Таким образом, обработка каждого сегмента будет производиться movable -методом.

(Отметим, что приведенное ниже решение пригодно и для случая, когда n не кратно p. Соответствующее обобщение может рассматриваться в качестве упражнения).

Разбиение исходного массива f на p сегментов производится таким образом, что в сегмент q, где ( 0 <= q < p ) попадают элементы f [ i ], такие что i mod p = q.

Так, например, если n = 16 и p = 4, то

0 -ой сегмент составят числа f [ 0 ], f [ 4 ], f [ 8 ], f [ 12 ] ;

1 -ый сегмент составят числа f [ 1 ], f [ 5 ], f [ 9 ], f [ 13 ]

и т.д.

Параллельный алгоритм вычисления частичных сумм будет устроен так, что q -му процессу ( movable -методу), обрабатывающему q -ый сегмент данных, достаточно будет общаться лишь с его соседями слева и справа (соответственно, 0 -му процессу - лишь с соседом справа, а последнему, (p-1) -му процессу - лишь с соседом слева) и главной программой для возврата результатов. Процесс с номером q будет вычислять все элементы h [j] результирующего массива, такие что j mod p = q, где 0 <= j < n.

Фрагмент главной программы, разбивающей исходный массив на сегменты и вызывающий movable -метод handleSegment, показан ниже. Здесь первым аргументом этого метода является номер сегмента, а последним - имя канала для возврата результатов.


Объекты класса BDChannel объявляются следующим образом :


Схема взаимодействия процессов ( movable -методов) между собой и главной программой показана ниже:


После разбиения, исходный массив f приобретает вид двумерной матрицы, распределенной по p процессам:

процесс 0: a0,0 a0,1 a0,m-1
процесс 1: a1,0 a1,1 a1,m-1
...
процесс q: aq,0 aq,1 aq,m-1
процесс p-1: ap-1,0 ap-1,1 ap-1,m-1

Другими словами, эта матрица получена из массива f разрезанием его на p сегментов и транспонированием каждого сегмента.

Ключевая идея алгоритма отдельного процесса q состоит в заполнении локальных для него массивов h0 и h1 (оба, имеющие размерность m ) в соответствии с формулами:

h0[i]=\sum\limits_{j=0}^{q-1}\sum\limits_{k=0}^i a_{j,k}\quad,\quad 0\le i<m,
h1[i]=\sum\limits_{j=q+1}^{p-1}\sum\limits_{k=0}^{i-1}a_{j,k}\quad,\quad 0\le i<m.

Неформально, это означает, что для процесса с номером q i -ый элемент массива h0 есть сумма всех элементов приведенной выше матрицы, которые расположены выше и слева элемента aq,i (включая и элементы столбца i ).

Аналогично, i -ый элемент массива h1 есть сумма всех элементов матрицы, которые расположены ниже и слева элемента aq,i (но, не включая элементов из столбца i ).

Ниже показана иллюстрация этого принципа для n = 16, p = 4 и q = 1, i = 2.


После того, как вычислены массивы h0 и h1 (посредством взаимодействия с соседними процессами), процесс с номером q может вычислить элемент h[i * p + q] результирующего массива как

h0[i]+\sum_{j=1}^i a_{q,j}+h1[i]\quad,\quad \mbox{для всех } i:\;0\le i<m.

Получаемые результирующие m значений процесс q сохраняет в локальном массиве h для передачи их главной программе. Тогда общая схема movable -метода handleSegment выглядит следующим образом:


Фрагмент программы, вычисляющий массив h0, приведен ниже.


Дмитрий Молокоедов
Дмитрий Молокоедов
Россия, Новосибирск, НГПУ, 2009
Паулус Шеетекела
Паулус Шеетекела
Россия, ТГТУ, 2010