Группы и коммуникаторы
Операции с коммуникаторами
Коммуникатор предоставляет отдельный контекст обмена процессов некоторой группы. Контекст обеспечивает возможность независимых обменов данными. Каждой группе процессов может соответствовать несколько коммуникаторов, но каждый коммуникатор в любой момент времени однозначно соответствует только одной группе.
Следующие коммуникаторы создаются сразу после вызова процедуры MPI_INIT:
- MPI_COMM_WORLD - коммуникатор, объединяющий все процессы приложения;
- MPI_COMM_NULL - значение, используемое для ошибочного коммуникатора;
- MPI_COMM_SELF - коммуникатор, включающий только вызвавший процесс.
Создание коммуникатора является коллективной операцией и требует операции межпроцессного обмена, поэтому такие процедуры должны вызываться всеми процессами некоторого существующего коммуникатора.
MPI_COMM_DUP(COMM, NEWCOMM, IERR) INTEGER COMM, NEWCOMM, IERR
Создание нового коммуникатора NEWCOMM с той же группой процессов и атрибутами, что и у коммуникатора сомм.
MPI_COMM_CREATE(COMM, GROUP, NEWCOMM, IERR) INTEGER COMM, GROUP, NEWCOMM, IERR
Создание нового коммуникатора NEWCOMM из коммуникатора сомм для группы процессов GROUP, которая должна являться подмножеством группы, связанной с коммуникатором сомм. Вызов должен встретиться во всех процессах коммуникатора сомм. На процессах, не принадлежащих группе GROUP, будет возвращено значение MPI_COMM_NULL.
В следующем примере создается две новых группы, одна из которых содержит первую половину процессов, а вторая - вторую половину. При нечетном числе процессов во вторую группу войдет на один процесс больше. Каждая группа создается только на тех процессах, которые в нее входят. Для каждой новой группы создается соответствующий ей коммуникатор new_comm, и операция MPI_ALLREDUCE выполняется по отдельности для процессов, входящих в разные группы.
call MPI_COMM_GROUP(MPI_COMM_WORLD, group, ierr) do i = 1, size/2 ranks(i) = i-1 end do if (rank .lt. size/2) then call MPI_GROUP_INCL(group, size/2, ranks, & new_group, ierr) else call MPI_GROUP_EXCL(group, size/2, ranks, & new_group, ierr) end if call MPI_COMM_CREATE(MPI_COMM_WORLD, new_group, & new_comm, ierr) call MPI_ALLREDUCE(sbuf, rbuf, 1, MPI_INTEGER, & MPI_SUM, new_comm, ierr) call MPI_GROUP_RANK(new_group, new_rank, ierr) print *, 'rank= ', rank, ' newrank= ', & new rank, ' rbuf= ', rbuf MPI_COMM_SPLIT(COMM, COLOR, KEY, NEWCOMM, IERR) INTEGER COMM, COLOR, KEY, NEWCOMM, IERR
Разбиение коммуникатора сомм на несколько новых коммуникаторов по числу значений параметра COLOR. В один коммуникатор попадают процессы с одним значением COLOR. Процессы с большим значением параметра KEY получат больший ранг в новой группе, при одинаковом значении параметра KEY порядок нумерации процессов выбирается системой.
Процессы, которые не должны войти в новые коммуникаторы, указывают в качестве параметра COLOR константу MPI_UNDEFINED. Им В параметре NEWCOMM вернется значение MPI_COMM_NULL.
В следующем примере коммуникатор MPI_COMM_WORLD разбивается на три части. В первую войдут процессы с номерами 0, 3, б и т.д., во вторую - 1, 4, 7 и т.д., а в третью - 2, 5, 8 и т.д. Задание в качестве параметра KEY переменной rank гарантирует, что порядок нумерации процессов в создаваемых группах соответствует порядку нумерации в исходной группе, то есть, порядку перечисления выше.
call MPI_COMM_SPLIT(MPI_COMM_WORLD, mod(rank, 3), & rank, new_comm, ierr) MPI_COMM_FREE(COMM, IERR) INTEGER COMM, IERR
Удаление коммуникатора сомм. После выполнения процедуры переменной сомм присваивается значение MPI_COMM_NULL. Если с этим коммуникатором к моменту вызова процедуры уже выполняется какая-то операция, то она будет завершена.
В следующем примере создается один новый коммуникатор comm_revs, в который входят все процессы приложения, пронумерованные в обратном порядке. Когда коммуникатор становится ненужным, он удаляется при помощи вызова процедуры MPI_COMM_FREE. Так можно использовать процедуру MPI_COMM_SPLIT для перенумерации процессов.
program example17 include 'mpif.h' integer ierr, rank, size integer comm_revs, rank1 call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) call MPI_COMM_SPLIT(MPI_COMM_WORLD, 1, size-rank, & comm_revs, ierr) call MPI_COMM_RANK(comm_revs, rank1, ierr) print *, 'rank = ', rank,' rank1 = ', rank1 call MPI_COMM_FREE(comm_revs, ierr) call MPI_FINALIZE(ierr) end
Задания
- Какие группы процессов существуют при запуске приложения?
- Могут ли группы процессов иметь непустое пересечение, не совпадающее ни с одной из них полностью?
- В чем отличие между группой процессов и коммуникатором?
- Могут ли обмениваться данными процессы, принадлежащие разным коммуникаторам ?
- Может ли в какой-то группе не быть процесса с номером О?
- Может ли в какую-либо группу не войти процесс с номером о в коммуникаторе MPI_COMM_WORLD?
- Может ли только один процесс в некоторой группе вызвать процедуру МРI_GROUP_INCL?
- Как создать новую группу из процессов 3, 4 и 7 коммуникатора МРI_COMM_WORLD?
- Разбить все процессы приложения на три произвольных группы и напечатать ранги в MPI_COMM_WORLD тех процессов, что попали в первые две группы, но не попали в третью.
- Какие коммуникаторы существуют при запуске приложения?
- Можно ли в процессе выполнения программы изменить число процессов в коммуникаторе MPI_COMM_WORLD?
- Может ли только один процесс в некотором коммуникаторе вызвать Процедуру MPI_COMM_CREATE?
- Можно ли при помощи процедуры MPI_COMM_SPLIT создать ровно один новый коммуникатор?
- Можно ли при помощи процедуры MPI_COMM_SPLIT создать столько новых коммуникаторов, сколько процессов входит в базовый коммуникатор?
- Реализовать разбиение процессов на две группы, в одной из которых осуществляется обмен данными по кольцу, а в другой - коммуникации по схеме master-slave.