Основы многопоточного и распределенного программирования

       

Взаимодействующие равные: распределенное умножение матриц


Ранее было показано, как реализовать параллельное умножение матриц с помощью про­цессов, разделяющих переменные. Здесь представлены два способа решения этой задачи с использованием процессов, взаимодействующих с помощью пересылки сообщений. Более сложные алгоритмы представлены в главе 9. Первая программа использует управляющий процесс и массив независимых рабочих процессов. Во второй программе рабочие процессы равны и их взаимодействие обеспечивается круговым конвейером. Рис. 1.7 иллюстрирует структуру схем взаимодействия этих процессов. Как показано в части 2, они часто встречают­ся в распределенных параллельных вычислениях.

На машинах с распределенной памятью каждый процессор имеет доступ только к собст­венной локальной памяти. Это значит, что программа не может использовать глобальные пе­ременные, поэтому любая переменная должна быть локальной для некоторого процесса и может быть доступной только этому процессу или процедуре. Следовательно, для взаимо­действия процессы должны использовать передачу сообщений.

Допустим, что нам необходимо получить произведение матриц а и Ь, а результат помес­тить в матрицу с. Предположим, что каждая из них имеет размер пхп и существует п процес­соров. Можно использовать массив из п рабочих процессов, поместив по одному на каждый процессор и заставив каждый рабочий процесс вычислять одну строку результирующей мат­рицы с. Программа для рабочих процессов будет выглядеть следующим образом.

process worker[i =  0  to n-1]   {

double a[n];       #  строка  i матрицы а double b[n,n];   #   вся  матрица b double c[n],-       #  строка  i матрицы с receive начальные значения вектора а и матрицы Ъ; for   [j   =  0  to n-1]   { c[j]   =  0.0; for   [k  =   0   to n-1]

c[j]   =  c[j]   +  a[k]   *  b[k,j]; }

send вектор-результат с управляющему процессу; }

Рабочий процесс i вычисляет строку i результирующей матрицы с. Чтобы это сделать, он должен получить строку i исходной матрицы а и всю исходную матрицу Ь.
Каждый рабочий процесс сначала получает эти значения от отдельного управляющего процесса. Затем рабочий процесс вычисляет свою строку результатов и отсылает ее обратно управляющему. (Или, воз­можно, исходные матрицы являются результатом предшествующих вычислений, а результи­рующая — входом для последующих; это пример распределенного конвейера.)

Управляющий процесс инициирует вычисления, собирает и выводит их результаты. В ча­стности, сначала управляющий процесс посылает каждому рабочему соответствующую стро­ку матрицы а и всю матрицу Ь. Затем управляющий процесс ожидает получения строк матри­цы с от каждого рабочего. Схема управляющего процесса такова.



36                                                                  Глава 1. Обзор области параллельных вычислений

receive строку i матрицы с от процесса worker [i],-вывести результат, который теперь в матрице с ;

}

Операторы send и receive, используемые управляющим процессом, — это примитивы (элементарные действия) передачи сообщений. Операция send упаковывает сообщение и пере­сылает его другому процессу; операция receive ожидает сообщение от другого процесса, а затем сохраняет его в локальных переменных. Подробно передача сообщений будет описана в главе 7 и использована в программировании многочисленных приложений в частях 2 и 3.

Как и ранее, предположим, что каждый рабочий процесс получает одну строку матрицы а и должен вычислить одну строку матрицы с. Однако теперь допустим, что у каждого процесса есть только один столбец, а не вся матрица Ь. Итак, в начальном состоянии рабочий процесс i имеет столбец i матрицы Ь. Имея лишь эти исходные данные, рабочий процесс может вы­числить только значение с [ i, i ]. Для того чтобы рабочий процесс i мог вычислить всю строку матрицы с, он должен получить все столбцы матрицы Ь. Для этого можно использо­вать круговой конвейер (см. рис. 1.7,б), в котором по рабочим процессам циркулируют, столбцы. Каждый рабочий процесс выполняет последовательность раундов; в каждом раунде ' он отсылает свой столбец матрицы Ь следующему процессу и получает другой ее столбец от предыдущего.


Программа имеет следующий вид.





В данной программе рабочие процессы упорядочены в соответствии с их индексами. (Для процесса п-1 следующим является процесс 0, а предыдущим для 0 — п-1.) Столбцы матри­цы Ь передаются по кругу между рабочими процессами, поэтому каждый процесс в конце концов получит каждый столбец. Переменная nextCol отслеживает, куда в векторе с помес­тить очередное промежуточное произведение. Как и в первом вычислении, предполагается, что управляющий процесс отправляет строки матрицы а и столбцы матрицы Ь рабочим, а за­тем получает от них строки матрицы с.

1 9. Обзор программной нотации                                                                                             37

Во второй программе использовано отношение между процессорами, которое называется взаимодействующие равные (interacting peers), или просто равные. Каждый рабочий процесс выпол­няет один и тот же алгоритм и взаимодействует с другими рабочими, чтобы вычислить свою часть необходимого результата. Дальнейшие примеры взаимодействующих равных мы увидим в частях 2 и 3. В одних случаях, как и здесь, каждый из рабочих процессов общается только с двумя своими соседями, в других — каждый из рабочих взаимодействует со всеми остальными процессами.

В первой из приведенных выше программ значения из матрицы Ь дублируются в каждом рабо­чем процессе. Во второй программе в любой момент времени у каждого процесса есть одна строка матрицы а и только один столбец матрицы Ь. Это снижает затраты памяти для каждого процесса, но вторая программа выполняется дольше первой, поскольку на каждой ее итерации каждый рабо­чий процесс должен отослать сообщение одному соседу и получить сообщение от другого. Дан­ные программы иллюстрируют классическое противоречие между временем и пространством в вычислениях. В разделе 9.3 представлены другие алгоритмы для распределенного умножения матриц, иллюстрирующие дополнительные противоречия между временем и пространством.


Содержание раздела