Перейдем к рассмотрению языков высокого уровня для программирования мультипроцессоров и мультикомпьютеров, которые используют SPMD-парадигму программирования (см. параграф 1). Будем называть далее такие языки высокого уровня SPMD-ЯВУ. Программу, написанную на SPMD-ЯВУ, будем называть SPMD-программами.
В SPMD-ЯВУ отсутствует понятие процесса и, как следствие, явная передача сообщений или явная синхронизация. В этом случае в последовательной программе данные распределяются программистом по процессорам многопроцессорной ЭВМ. Компилятором последовательная программа преобразуется в параллельную программу, в которой обмены данными выполняются с использованием модели обмена данными посредством передачи сообщений. При этом каждый процессор выполняет обработку только тех данных, которые распределены на этот процессор.
SPMD-ЯВУ обладают следующими достоинствами.
  1. Параллелизм данных, который используют SPMD-ЯВУ, является естественным параллелизмом для многих вычислительных задач, в которых по одним и тем же формулам производится обработка множества элементов массивов.
  2. При использовании SPMD-ЯВУ программист не должен представлять программу в виде взаимодействующих процессов и заниматься низкоуровневым программированием передач сообщений и синхронизации.
  3. Локализация данных на процессорах многопроцессорной системы, которую используют SPMD-ЯВУ, ускоряет работу процессоров, поскольку в этом случае лучше используется кэш-память, меньше пересылок данных с других процессоров и т.д.
Заметим, что если задача пользователя обладает функциональным параллелизмом, то модели обмена данными посредством передачи сообщений нет альтернативы. В этом случае организовать параллельное решение задачи можно только так, что каждый процессор многопроцессорной системы выполняет алгоритм, существенно отличающийся от того, который реализуют другие процессоры. И ничего другого, кроме использования MPMD-языка высокого уровня предложить, практически, невозможно.
Наиболее известным SPMD-языком высокого уровня является HPF (High Performance Fortran), который представляет собой расширение языка Фортран 90. Аналогичные расширения существуют для языков Си и Си++.
Поддержка параллелизма данных в HPF.
Общий стиль параллельного программирования на языке высокого уровня HPF:
Директива PROCESSORS. С помощью этой директивы объявляются абстрактные процессоры, на которые могут быть распределены данные. Средства отображения абстрактных процессоров на физические процессоры в языке HPF отсутствуют.
Например, директива
!HPF$ PROCESSORS P(8)
вводит 8 абстрактных процессоров, объединенных коммуникационной сетью с топологией типа "линейка". Здесь префикс !HPF$ — признак директивы.
Аналогично, директива
!HPF$ PROCESSORS PROC(8,8)
вводит 64 абстрактных процессора, объединенных коммуникационной сетью с топологий типа "двумерная решетка".
Поскольку при разработке программы может быть неизвестно количество физических процессоров в вычислительной системе, в языке HPF существуют две следующие встроенные функции:
функция NUMBER_OF_PROCESSORS() возвращает количество физических процессоров в системе;
функция PROCESOS_SHAPE() возвращает топологию коммуникационной сети процессоров в системе.
Таким образом, в языке HPF допустима директива
!HPF$ PROCESSORS PR(NUMBER_OF_PROCESSORS ()/2)
которая вводит число абстрактных процессоров, в два раза меньшее числа физических процессоров в системе.
Директивы DISTRIBUTE и REDISTRIBUTE. Директива DISTRIBUTE определяет способ разбиения массива и управляем размещением частей массива в памяти абстрактных процессоров. Директива REDISTRIBUTE является выполняемой и обеспечивает динамическое распределение данных во время выполнения программы.
В языке HPF имеется два способа распределения данных: блочный и циклический.
При блочном распределении массива по процессорам массив разделяется на равные части (блоки) в порядке расположения элементов в массиве. Последний блок может содержать меньшее количество элементов.
Пример 1
      REAL, DIMESION ARRAY1(1000)
!HPF$ PROCESSORS PROC1(5)
!HPF$ DISTRIBUTE(BLOCK) ONTO PROC1 :: ARRAY1
Данный фрагмент программы специфицирует массив ARRAY1 из 1000 элементов, 5 абстрактных процессоров c именами PROC1(1), …, PROC1(5), а также разбивает указанный массив на блоки по 200 элементов в каждом и размещает первые 200 элементов массива ARRAY1 на процессоре PROC1(1), вторые 200 элементов – на процессоре PROC1(2) и т.д
Размер блоков может быть также указан явно.
При циклическом распределении массива по процессорам первая часть массива назначается на первый процессор, вторая часть – на второй процессор и т.д. до исчерпания процессоров. Затем, если массив не исчерпан, процесс повторяется – очередная часть массива назначается на первый процессор, следующая – на второй и т.д.
Пример 2
      REAL DIMESION ARRAY2(10000)
!HPF$ PROCESSORS PROC2(10)
!HPF$ DISTRIBUTE (СYCLIC 100) ONTO PROC2 :: ARRAY2
Данный фрагмент программы разбивает массив ARRAY2 на блоки по 100 элементов в каждом и размещает их следующим образом:
  • на процессоре PROC2(1) элементы с 1 по 100, с 1001 по 1100, с 2001 по 2100 и т.д.;
  • на процессоре PROC2(1) элементы с 101 по 200, с 1101 по 1200, с 2101 по 2100 и т.д.;
Для многомерного массива можно указывать способ распределения по каждому из его измерений.
Директивы ALIGN и REALIGN. Директива ALIGN используется для организации статического согласованного распределения массивов по процессорам. Директива указывает компилятору, что данный массив должен быть распределен по процессорам так же, как некоторый другой массив. Такое распределение массивов по процессорам может потребоваться, например, в случае, когда эти массивы обрабатываются в одном распараллеливаемом цикле.
Пример 3
      REAL DIMESION ARRAY1(1000), ARRAY2(1000)
!HPF$ PROCESSORS PROC1(5)
!HPF$ DISTRIBUTE (BLOCK) ONTO PROC1 :: ARRAY1
!HPF$ ALIGN ARRAY2(:) WITH ARRAY1(:)
Данный фрагмент программы вызывает такое же распределение элементов массива ARRAY2 по процессорам PROC1(1), …, PROC1(5), как и распределение по этим процессорам элементов массива ARRAY1 (см. прим. 1)
Аналогично, директива REALIGN выполняет динамическое согласованное распределение элементов массивов во время выполнения программы.
Директива TEMPLATE. Директива TEMPLATE позволяет выполнить согласованное распределение массивов по процессорам с помощью абстрактного массива – шаблона.
Пример 4
      REAL, DIMESION ARRAY3(1000)
!HPF$ PROCESSORS PROC3(5)
!HPF$ TEMPLATE, DIMESION T(1000)
!HPF$ DISTRIBUTE (BLOCK) ONTO PROC3 :: T
!HPF$ ALIGN ARRAY3(:) WITH T(:)
Шаблон (Т — в данном примере) объявляется как обычный массив, но не имеет элементов
Для распараллеливания циклов язык HPF использует специальные конструкции языка (оператор FORALL) и директиву INDEPENDENT.
По сравнению с MPI (см. параграф 7) язык HPF намного упрощает написание параллельных программ. Программы на языке HPF существенно короче функционально идентичных программ, использующих прямые вызовы функций обмена сообщениями.
Реализация язык HPF требует от компилятора очень высокого уровня интеллекта. Известны эксперименты, показывающие, что в большинстве случаев эффективность параллельных HPF-программ значительно ниже эффективности соответствующих MPI-программ.