Обзор способов параллельного программирования

В этой статье подробно рассматриваются различные подходы к параллельному программированию.
Наиболее широкоизвестные способы параллельного программирования

  1. Threads / Processes
  2. OpenMP
  3. MPI

Исторически сложилось так, что наиболее часто применяемый способ — это Threads в их различных реинкарнациях. Способ хорош тем что не требует дополнительных библиотек. Чтобы использовать этот вариант, достаточно имеющихся возможностей OC. Обычно используется для скрытия от пользователя различных продолжительных операций, чтобы не терять возможность отрисовки GUI в момент ожидания операции. Основное достоинство — потоки разделяют адресное пространства и принадлежат одному процессу. Поэтому все передачи данных между потоками выполняются максимально быстро. Чаще всего достаточно передать указатель. Синхронизация потоков не затратна и не требует системных вызовов (Syscall) — долгих операций с переключением контекста. Сюда же можно отнести и многопроцессные программы в самом простейшем виде — использующие fork() или что-то подобное из системных функций для порождения нового процесса, но применяющее для синхронизации и обмена данными системное API.
Для более простого распараллеливания уже существующего кода был придуман OpenMP. Больщинство работы по распараллеливанию и синхронизации здесь переложена на компилятор и его библиотеки. Для распараллеливания достаточно разместить определенные прагмы (#pragma …) в коде программы. Набор этих прагм описан в стандарте. Плюс такого подхода — легкость обретения параллелизма программой. Недостатки — требуется специальный компилятор, низкий уровень параллельности, необходимость следования навязываемой парадигме.

MPI (Message Passing Interface). Эта библиотека, как следует из названия не предназначена для какого либо распараллеливания, однако ее чаще всего применяют для написания параллельных программ на больших кластерах. Именно для написания, так как для применения MPI плохо подходит вариант «напишем последовательный код, а потом распараллелим». В варианте с MPI программа сразу представляет собой N процессов. Это N фиксировано и задается параметром при запуске приложения. Т.е. это полный параллелизм, а библиотека предоставляет примитивы для синхронизации и обмена данными. К плюсам применения MPI относят высокую масштабируемость решения, высокий уровень параллельности и отличная портабельность кода. Основные минусы — сложности при программировании, относительно высокие затраты на синхронизацию и обмен данными.

Кроме основных трех способов существуют еще и другие малоизвестные, малоприменимые и/или устаревшие. Такие как GlobalArrays — распределенные структуры данных со скрытым доступом к элементам, PVM — прародитель MPI… Может еще чего есть — напишите мне, если знаете 🙂

Как это выглядит

Здесь я минимально приведу код, чтобы его можно было охватить глазами. Объяснять как это работает здесь смысла нет, для этого будут отдельные темы.

1. Создание двух процессов вызовом fork():

int main(){
...
pid = fork();
if (pid == 0) {
// код потомка
else{
// код родителя}
...}

2. Использование прагм openmp()

 int main(){
...
#pragma parallel for
for (int i=0; i<MaxI; i++)// Параллельный цикл
...

}

3. Использование MPI

int main(int* argc, char ** argv){//код идет параллельно начиная с ф-ции main()
//Обязательный пролог - инициализация MPI
MPI_Init(int* argc, char ** argv);
MPI_Comm_size(&np);
MPI_Comm_rank(&myrank);
printf("I'm process %i, from %i total", myrank, np);
//обязательный эпилог
MPI_Finalize();
}

dmitry

5 Comments

  1. я новичек в параллельном программировании но выбрал сразу опен мп
    1) не знаю чем вам не нравится парадигма.
    вполне нармуль парадигма!
    пишеш себе последовательный кодик и не париш мозг
    2) никакой не нуна специальный компилятор
    обычный gcc нуна! (или вижуал начиная с 2005)

  2. 2metaluga
    Во-первых, сравнивать парадигмы, лучше в рамках какой-то конкретной задачи, во-вторых, как правило, сложные задачи делают гибридными (на кластере выделяют несколько узлов, и считают на каждом из них часть задачи с использованием нескольких процессоров), в-третьих, в OpenMP все не так просто. Действительно, если вычислять число пи, то задача параллелится на раз два, в задчах же посложнее (например, где необходимо обойти дерево) возникают кэш-промахи, узкие места (когда все процессы ждут одного) и прочяя неприятность.

  3. Доброго времени суток! Извините, что сдесь публикую.
    Вопрос такого рода: в программе планирую использовать дополнительный процессор как и GPU, так и FPGA… есть ли методы, для автоматического использования либо того, либо другого устройства, или есть возможность двух сразу?

  4. Смотря что понимать под автоматическим использованием. В общем случае для OpenMP вы расставляете прагмы и получаете паралельное исполнение. Про FPGA ничего сказать не могу — не испльзовал.

Добавить комментарий