Теория и практика параллельных вычислений

         

Управление коммуникаторами


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

Для создания новых коммуникаторов существуют два основных способа:

  • дублирование уже существующего коммуникатора:

int MPI_Comm_dup(MPI_Comm oldcom, MPI_comm *newcom),

где

  • oldcom — существующий коммуникатор, копия которого создается;
  • newcom — новый коммуникатор;
  • создание нового коммуникатора из подмножества процессов существующего коммуникатора:

int MPI_comm_create(MPI_Comm oldcom, MPI_Group group, MPI_Comm *newcom),

где

  • oldcom — существующий коммуникатор;
  • group — подмножество процессов коммуникатора oldcom;
  • newcom — новый коммуникатор.

Дублирование коммуникатора может применяться, например, для устранения возможности пересечения по тегам сообщений в разных частях параллельной программы (в том числе и при использовании функций разных программных библиотек).

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

Для пояснения рассмотренных функций можно привести пример создания коммуникатора, в котором содержатся все процессы, кроме процесса, имеющего ранг 0 в коммуникаторе MPI_COMM_WORLD (такой коммуникатор может быть полезен для поддержки схемы организации параллельных вычислений "менеджер – исполнители" – см. лекцию 4):

MPI_Group WorldGroup, WorkerGroup; MPI_Comm Workers; int ranks[1]; ranks[0] = 0; // Получение группы процессов в MPI_COMM_WORLD MPI_Comm_group(MPI_COMM_WORLD, &WorldGroup); // Создание группы без процесса с рангом 0 MPI_Group_excl(WorldGroup, 1, ranks, &WorkerGroup); // Создание коммуникатора по группе MPI_Comm_create(MPI_COMM_WORLD, WorkerGroup, &Workers); ... MPI_Group_free(&WorkerGroup); MPI_Comm_free(&Workers);

Быстрый и полезный способ одновременного создания нескольких коммуникаторов обеспечивает функция:


int MPI_Comm_split( MPI_Comm oldcomm, int split, int key, MPI_Comm *newcomm),

где

  • oldcomm — исходный коммуникатор;
  • split — номер коммуникатора, которому должен принадлежать процесс;
  • key — порядок ранга процесса в создаваемом коммуникаторе;
  • newcomm — создаваемый коммуникатор.


Создание коммуникаторов относится к коллективным операциям, и поэтому вызов функции MPI_Comm_split должен быть выполнен в каждом процессе коммуникатора oldcomm. В результате выполнения функции процессы разделяются на непересекающиеся группы с одинаковыми значениями параметра split. На основе сформированных групп создается набор коммуникаторов. Для того чтобы указать, что процесс не должен входить ни в один из создаваемых коммуникаторов, необходимо воспользоваться константой MPI_UNDEFINED в качестве значения параметра split. При создании коммуникаторов для рангов процессов в новом коммуникаторе выбирается такой порядок нумерации, чтобы он соответствовал порядку значений параметров key (процесс с большим значением параметра key получает больший ранг, процессы с одинаковым значением параметра key сохраняют свою относительную нумерацию).

В качестве примера можно рассмотреть задачу представления набора процессов в виде двумерной решетки. Пусть p=q*q есть общее количество процессов; следующий далее фрагмент программы обеспечивает получение коммуникаторов для каждой строки создаваемой топологии:

MPI_Comm comm; int rank, row; MPI_Comm_rank(MPI_COMM_WORLD, &rank); row = rank / q; MPI_Comm_split(MPI_COMM_WORLD, row, rank, &comm);

При выполнении данного примера, например, при p=9, процессы с рангами (0, 1, 2) образуют первый коммуникатор, процессы с рангами (3, 4, 5) – второй и т. д.

После завершения использования коммуникатор должен быть удален, для чего используется функция:

int MPI_Comm_free(MPI_Comm *comm),

где

  • comm — коммуникатор, подлежащий удалению.



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