1 1 Структура параллельной программы

Структура параллельной программы в большой степени зависит от численных методов, используемых для ее решения, выбора языка программирования, компиляторов, а так же от самой задачи. Однако можно выделить независящие от этих факторов структурные особенности. Любая программа, выполняемая на кластерном компьютере, должна выполнять определенную последовательность действий, которую (последовательность) можно представить в виде виде отдельных алгоритмических блоков. В общем виде эта последовательность может выглядеть примерно таким вот образом:

1.              program test
2.              <инициализация параллельной среды>
3.              N=<номер текущего процессора>
4.              <загрузка массивов данных для процеса N>
5.              while(<задача не решена>) do
6.                      <получение и передача граничных данных>
7.                      <выполнение очередной итерации>
8.                      if(<контрольная точка>) then
9.                              <сохранение данных на диск>
10.             done
11.             <деинициализация параллельной среды>
12.             end
13.             stop

Более подробно прокоментируем каждый из шагов программы.

Строка N1. Начало программы.

Строка N2. Действие, производимое на этом шаге вполне понятно. Здесь мы выполняем некоторые операции для подготовки к работе параллельной вычислительной среды. Конкретный программный код этого шага зависит от языка программирования и выбранной параллельной среды (MPICH/MPI/PVM).

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

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

Строка N5. Это начало нашего итерационного процесса. Здесь же мы по каким-то критериям решаем, достигнут ли желаемый результат, и не пора ли завершить программу.

Строка N6. Перед выполнением собственно итерации, мы должны получить данные от соседних процессов для граничных областей локальных массивов.

Строка N7. Собственно обработка массивов данных в соответствии с задачами, возложенными на процесс номер N. То есть очередной шаг итерации.

Строка N8. После завершения очередной порции вычислений мы должны решить, не наступил ли момент сохранить промежуточные результаты на диск. То есть, не достигли ли мы контрольной точки. Как часто это делать - решать программисту. Однако разумным будет сохранять данные не на каждой итерации, а гораздо реже. Так, чтобы время, необходимое для записи на диск, было много меньше, чем длительность итераций между контрольными точками. Таким образом мы снизим отрицательный влияние на быстродействие кластера такой медленной операции, как сохранение данных на винчестер.

Строка N9. Если мы решили, что достигли контрольной точки, то в этом месте программы мы начинаем процедуру сохранения данных. Причем, выполнять запись данных на диск необходимо (по мере возможности) в асинхронном режиме. Действительно, если мы, например, решаем систему ДУ газодинамики, мы имеем (опять же к примеру) два массива, соответствующих двум временным слоям. Предыдущий слой по времени никак не меняется в процессе вычислений. Поэтому сохранять его на диск имеет смысл параллельно вычислениям, производимым над текущим временным слоем. Естественно, не надо забывать проверять, закончился ли процесс записи перед тем, как возникнет необходимость как-либо изменить массив, который мы сохраняем на диск.

Строка N10. Конец итерационного цикла. Ничего более.

Строка N11. В самом конце работы программы мы должны корректно завершить работу параллельной среды. Чем мы и занимаемся на этом шаге. Здесь же мы можем сохранить на диск финальные данные, которые мы мы можем как-то анализировать или использовать в качестве начальных данных при последующем запуске нашей программы.


Copyright © 1998-2011 Юрий Сбитнев