Программирование для многопроцессорных систем в стандарте MPI - Шпаковский Г.И., Серикова Н.В.. Программирование для многопроцессорных систем в стандарте MPI -. Организация вычислений в многопроцессорных системах
Скачать 1.61 Mb.
|
Глава 5. ГРУППЫ И КОММУНИКАТОРЫ 5.1. ВВЕДЕНИЕ В этом разделе рассматриваются средства MPI для поддержки раз- работки параллельных библиотек. Для создания устойчивых парал- лельных библиотек интерфейс MPI должен обеспечить: • Возможность создавать безопасное коммуникационное простран- ство, которое гарантировало бы, что библиотеки могут выполнять обмен, когда им нужно, без конфликтов с обменами, внешними по отношению к данной библиотеке. • Возможность определять границы области действия коллективных операций, которые позволяли бы библиотекам избегать ненужного запуска невовлеченных процессов. • Возможность абстрактного обозначения процессов, чтобы библио- теки могли описывать свои обмены в терминах, удобных для их собственных структур данных и алгоритмов. • Возможность создавать новые пользовательские средства, такие как дополнительные операции для коллективного обмена. Этот механизм должен обеспечить пользователя или создателя библио- теки средствами эффективного расширения состава операций для передачи сообщений. Для поддержки библиотек MPI обеспечивает группы процессов (groups), виртуальные топологии (virtual topologies), коммуникаторы (communicators). Коммуникаторы создают область для всех операций обмена в MPI. Коммуникаторы разделяются на два вида: интра-коммуникаторы (внутригрупповые коммуникаторы), предназначенные для операций в пределах отдельной группы процессов, и интер-коммуникаторы (меж- групповые коммуникаторы), предназначенные для обменов между двумя группами процессов. Группы. Группы определяют упорядоченную выборку процессов по именам. Таким образом, группы определяют область для парных и коллективных обменов. В MPI группы могут управляться отдельно от коммуникаторов, но в операциях обмена могут использоваться только коммуникаторы. Виртуальная топология определяет специальное отображение номеров процессов в группе на определенную топологию, и наоборот. 144 Чтобы обеспечить эту возможность, в главе 6 для коммуникаторов определены специальные конструкторы. 5.2. БАЗОВЫЕ КОНЦЕПЦИИ Группа есть упорядоченный набор идентификаторов процессов; процессы есть зависящие от реализации объекты. Каждый процесс в группе связан с целочисленным номером. Нумерация является непре- рывной и начинается с нуля. Группы представлены скрытыми объек- тами группы и, следовательно, не могут быть непосредственно пере- даны от одного процесса к другому. Группа используется в пределах коммуникатора для описания участников коммуникационной области и ранжирования этих участников путем предоставления им уникаль- ных имен. Имеется предопределенная группа: MPI_GROUP_EMPTY , кото- рая является группой без членов. Предопределенная константа MPI_GROUP_NULL является значением, используемым для оши- бочных дескрипторов группы. Контекст есть свойство коммуникаторов, которое позволяет раз- делять пространство обмена. Сообщение, посланное в одном контек- сте, не может быть получено в другом контексте. Более того, где это разрешено, коллективные операции независимы от ждущих операций парного обмена. Контексты не являются явными объектами MPI; они проявляются только как часть реализации коммуникаторов. Интра-коммуникаторы объединяют концепции группы и контек- ста для поддержки реализационно-зависимых оптимизаций и при- кладных топологий (глава 6). Операции обмена в MPI используют коммуникаторы для определения области, в которой должны выпол- няться парная или коллективная операции. Каждый коммуникатор содержит группу участников; эта группа всегда участвует в локальном процессе. Источник и адресат сообще- ния определяются номером процесса в пределах этой группы. Для коллективной связи интра-коммуникатор определяет набор процессов, которые участвуют в коллективной операции (и их поря- док, когда это существенно). Таким образом, коммуникатор ограни- чивает "пространственную" область коммуникации и обеспечивает машинно-независимую адресацию процессов их номерами. Начальный для всех возможных процессов интра-коммуникатор MPI_COMM_WORLD создается сразу при обращении к функции MPI_INIT . Кроме того, существует коммуникатор, который cодержит 145 только себя как процесс – MPI_COMM_SELF . Предопределенная константа MPI_COMM_NULL есть значение, используемое для не- верных дескрипторов коммуникатора. В реализации MPI со статической моделью обработки коммуника- тор MPI_COMM_WORLD имеет одинаковое значение во всех про- цессах. В реализации MPI, где процессы могут порождаться динами- чески, возможен случай, когда процесс начинает вычисления, не имея доступа ко всем другим процессам. В таких ситуациях, коммуникатор MPI_COMM_WORLD является коммуникатором, включающим все процессы, с которыми подключающийся процесс может немедленно связаться. Поэтому MPI_COMM_WORLD может одновременно иметь различные значения в различных процессах. Все реализации MPI должны обеспечить наличие коммуникатора MPI_COMM_WORLD . Он не может быть удален в течение времени существования процесса. Группа, соответствующая этому коммуника- тору, не появляется как предопределенная константа, но к ней можно обращаться, используя MPI_COMM_GROUP MPI не определяет со- ответствия между номером процесса в MPI_COMM_WORLD и его абсолютным адресом. 5.3. УПРАВЛЕНИЕ ГРУППОЙ Операции управления являются локальными, и их выполнение не требует межпроцессного обмена. 5.3.1. Средства доступа в группу MPI_GROUP_SIZE (group, size) IN group группа (дескриптор) OUT size количество процессов в группе (целое) int MPI_Group_size(MPI_Group group, int *size) MPI_GROUP_SIZE(GROUP, SIZE, IERROR) INTEGER GROUP, SIZE, IERROR int MPI::Group::Get_size() const Функция MPI_GROUP_SIZE позволяет определить размер группы. MPI_GROUP_RANK (group, rank) IN group группа (дескриптор) OUT rank номер процесса в группе или MPI_UNDEFINED, если процесс не является членом группы (целое) 146 int MPI_Group_rank(MPI_Group group, int *rank) MPI_GROUP_RANK(GROUP, RANK, IERROR) INTEGER GROUP, RANK, IERROR int MPI::Group::Get_rank() const Функция MPI_GROUP_RANK служит для определения номера процесса в группе. MPI_GROUP_TRANSLATE_RANKS(group1, n, ranks1, group2, ranks2) IN group1 Группа1 (дескриптор) IN n число номеров в массивах ranks1 и ranks2 (целое) IN ranks1 массив из нуля или более правильных номеров в группе1 IN group2 группа2 (дескриптор) OUT ranks2 массив соответствующих номеров в группе2, MPI_UNDEFINED, если соответствие отсутствует. int MPI_Group_translate_ranks (MPI_Group group1, int n, int *ranks1, MPI_Group group2, int *ranks2) MPI_GROUP_TRANSLATE_RANKS(GROUP1, N, RANKS1, GROUP2, RANKS2, IERROR) INTEGER GROUP1, N, RANKS1(*), GROUP2, RANKS2(*), IERROR static void MPI::Group::Translate_ranks(const MPI::Group& group1, int n, const int ranks[], const MPI::Group& group2, int ranks2[]) Эта функция важна для определения относительной нумерации одинаковых процессов в двух различных группах. Например, если из- вестны номера некоторых процессов в MPI_COMM_WORLD , то можно узнать их номера в подмножестве этой группы. MPI_GROUP_COMPARE(group1, group2, result) IN group1 первая группа (дескриптор) IN group2 вторая группа (дескриптор) OUT result результат (целое) int MPI_Group_compare(MPI_Group group1,MPI_Group group2, int *result) MPI_GROUP_COMPARE(GROUP1, GROUP2, RESULT, IERROR) INTEGER GROUP1, GROUP2, RESULT, IERROR static int MPI::Group::Compare(const MPI::Group& group1, const MPI::Group& group2) Если члены группы и их порядок в обеих группах совершенно одинаковы, вырабатывается результат MPI_IDENT . Это происходит, 147 например, если group1 и group2 имеют тот же самый дескриптор. Ес- ли члены группы одинаковы, но порядок различен, то вырабатывается результат MPI_SIMILAR . В остальных случаях получается значение MPI_UNEQUAL 5.3.2. Конструкторы групп Конструкторы групп применяются для подмножества и расши- ренного множества существующих групп. Эти конструкторы создают новые группы на основе существующих групп. Данные операции яв- ляются локальными, и различные группы могут быть определены на различных процессах; процесс может также определять группу, кото- рая не включает себя. MPI не имеет механизма для формирования группы с нуля – груп- па может формироваться только на основе другой, предварительно определенной группы. Базовая группа, на основе которой определены все другие группы, является группой, связанной с коммуникатором MPI_COMM_WORLD (через функцию MPI_COMM_GROUP ). MPI_COMM_GROUP(comm, group) IN comm коммуникатор (дескриптор) OUT group группа, соответствующая comm (дескриптор) int MPI_Comm_group(MPI_Comm comm, MPI_Group *group) MPI_COMM_GROUP(COMM, GROUP, IERROR) INTEGER COMM, GROUP, IERROR MPI::Group MPI::Comm::Get_group() const Функция MPI_COMM_GROUP возвращает в group дескриптор группы из comm. MPI_GROUP_UNION(group1, group2, newgroup) IN group1 первая группа (дескриптор) IN group2 вторая группа (дескриптор) OUT newgroup объединенная группа (дескриптор) int MPI_Group_union(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup) MPI_GROUP_UNION(GROUP1, GROUP2, NEWGROUP, IERROR) INTEGER GROUP1, GROUP2, NEWGROUP, IERROR static MPI::Group MPI::Group::Union(const MPI::Group& group1, const MPI::Group& group2) 148 Операции над множествами определяются следующим образом: • Объединение ( union ) – содержит все элементы первой группы ( group1 ) и следующие за ними элементы второй группы ( group2 ), не входящие в первую группу. • Пересечение ( intersect ) – содержит все элементы первой группы, которые также находятся во второй группе, упорядоченные, как в первой группе. • Разность ( difference ) – содержит все элементы первой группы, ко- торые не находятся во второй группе. MPI_GROUP_INTERSECTION(group1, group2, newgroup) IN group1 первая группа (дескриптор) IN group2 вторая группа (дескриптор) OUT newgroup группа, образованная пересечением (дескриптор) int MPI_Group_intersection(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup) MPI_GROUP_INTERSECTION(GROUP1, GROUP2, NEWGROUP, IERROR) INTEGER GROUP1, GROUP2, NEWGROUP, IERROR static MPI::Group MPI::Group::Intersect(const MPI::Group& group1, const MPI::Group& group2) MPI_GROUP_DIFFERENCE(group1, group2, newgroup) IN group1 первая группа(дескриптор) IN group2 вторая группа (дескриптор) OUT newgroup исключенная группа (дескриптор) int MPI_Group_difference(MPI_Group group1, MPI_Group group2, MPI_Group *newgroup) MPI_GROUP_DIFFERENCE(GROUP1, GROUP2, NEWGROUP, IERROR) INTEGER GROUP1, GROUP2, NEWGROUP, IERROR static MPI::Group MPI::Group::Difference(const MPI::Group& group1, const MPI::Group& group2) Для этих операций порядок процессов в результирующей группе определен, прежде всего, в соответствии с порядком в первой группе и затем, в случае необходимости, в соответствии с порядком во вто- рой группе. Ни объединение, ни пересечение не коммутативны, но обе ассоциативны. Новая группа может быть пуста (эквивалентна MPI_GROUP_EMPTY) 149 MPI_GROUP_INCL(group, n, ranks, newgroup) IN group группа (дескриптор) IN n количество элементов в массиве номеров (и размер newgroup, целое) IN ranks номера процессов в group, перешедших в новую группу (массив целых) OUT newgroup новая группа, полученная из прежней, упорядоченная согласно ranks (дескриптор) int MPI_Group_incl(MPI_Group group, int n, int *ranks, MPI_Group *newgroup) MPI_GROUP_INCL(GROUP, N, RANKS, NEWGROUP, IERROR) INTEGER GROUP, N, RANKS(*), NEWGROUP, IERROR MPI::Group MPI::Group::Incl(int n, const int ranks[]) const Функция MPI_GROUP_INCL создает группу newgroup , которая состоит из n процессов из group с номерами rank[0],..., rank[n-1]; процесс с номером i в newgroup есть процесс с номером ranks[i] в group . Каждый из n элементов ranks должен быть правильным номе- ром в group , и все элементы должны быть различными, иначе про- грамма будет неверна. Если n = 0 , то newgroup имеет значение MPI_GROUP_EMPTY . Эта функция может, например, использо- ваться, чтобы переупорядочить элементы группы. MPI_GROUP_EXCL(group, n, ranks, newgroup) IN group группа (дескриптор) IN n количество элементов в массиве номеров (целое) IN ranks массив целочисленных номеров в group, не входящих в newgroup OUT newgroup новая группа, полученная из прежней, сохраняющая порядок, определенный group (дескриптор) int MPI_Group_excl(MPI_Group group, int n, int *ranks, MPI_Group *newgroup) MPI_GROUP_EXCL(GROUP, N, RANKS, NEWGROUP, IERROR) INTEGER GROUP, N, RANKS(*), NEWGROUP, IERROR MPI::Group MPI::Group::Excl(int n, const int ranks[]) const Функция MPI_GROUP_EXCL создает группу newgroup , которая получена путем удаления из group процессов с номерами ranks[0] ,... ranks[n-1]. Упорядочивание процессов в newgroup идентично упоря- дочиванию в group . Каждый из n элементов ranks должен быть пра- вильным номером в group , и все элементы должны быть различными; 150 в противном случае программа неверна. Если n = 0 , то newgroup идентична group 5.3.3. Деструкторы групп MPI_GROUP_FREE(group) INOUT group идентификатор группы (дескриптор) int MPI_Group_free(MPI_Group *group) MPI_GROUP_FREE(GROUP, IERROR) INTEGER GROUP, IERROR void MPI::Group::Free() Эта операция маркирует объект группы для удаления. Дескриптор group устанавливается вызовом в состояние MPI_GROUP_NULL Любая выполняющаяся операция, использующая эту группу, завер- шитcя нормально. 5.4. УПРАВЛЕНИЕ КОММУНИКАТОРАМИ Этот параграф описывает управление коммуникаторами в MPI Операции обращения к коммуникаторам являются локальными, их выполнение не требует обмена между процессами. Операции, которые создают коммуникаторы, являются коллективными и могут потребо- вать обмена между процессами. 5.4.1. Доступ к коммуникаторам Все следующие операции являются локальными. MPI_COMM_SIZE(comm, size) IN comm коммуникатор (дескриптор) OUT size количество процессов в группе comm (целое) int MPI_Comm_size(MPI_Comm comm, int *size) MPI_COMM_SIZE(COMM, SIZE, IERROR) INTEGER COMM, SIZE, IERROR int MPI::Comm::Get_size() const Эта функция указывает число процессов в коммуникаторе. Для MPI_COMM_WORLD она указывает общее количество доступных процессов. 151 MPI_COMM_RANK(comm, rank) IN comm коммуникатор (дескриптор) OUT rank номер вызывающего процесса в группе comm (целое) int MPI_Comm_rank(MPI_Comm comm, int *rank) MPI_COMM_RANK(COMM, RANK, IERROR) INTEGER COMM, RANK, IERROR int MPI::Comm::Get_rank() const Функция MPI_COMM_RANK возвращает номер процесса в част- ной группе коммуникатора. Ее удобно использовать cовместно с MPI_COMM_SIZE MPI_COMM_COMPARE(comm1, comm2, result) IN comm1 первый коммуникатор (дескриптор) IN comm2 второй коммуникатор (дескриптор) OUT result результат (целое) int MPI_Comm_compare(MPI_Comm comm1,MPI_Comm comm2, int *result) MPI_COMM_COMPARE(COMM1, COMM2, RESULT, IERROR) INTEGER COMM1, COMM2, RESULT, IERROR static inc MPI::Comm::Compare(const MPI::Comm& comm1, const MPI::Comm& comm2) Результат MPI_IDENT появляется тогда и только тогда, когда comm1 и comm2 являются дескрипторами для одного и того же объ- екта. Результат MPI_CONGRUENT появляется, если исходные груп- пы идентичны по компонентам и нумерации; эти коммуникаторы от- личаются только контекстом. Результат MPI_SIMILAR имеет место, если члены группы обоих коммуникаторов являются одинаковыми, но порядок их нумерации различен. В противном случае выдается ре- зультат MPI_UNEQUAL 5.4.2. Конструкторы коммуникаторов Нижеперечисленные функции являются коллективными и вызы- ваются всеми процессами в группе, связанной с comm . В MPI для соз- дания нового коммуникатора необходим исходный коммуникатор. Основным коммуникатором для всех MPI коммуникаторов является коммуникатор MPI_COMM_WORLD. 152 Функция MPI_COMM_DUP дублирует существующий комму- никатор comm, возвращает в аргументе newcomm новый коммуника- тор с той же группой. MPI_COMM_DUP(comm, newcomm) IN comm коммуникатор (дескриптор) OUT newcomm копия comm (дескриптор) int MPI_Comm_dup(MPI_Comm comm, MPI_Comm *newcomm) MPI_COMM_DUP(COMM, NEWCOMM, IERROR) INTEGER COMM, NEWCOMM, IERROR MPI::Intracomm MPI::Intracomm::Dup() const MPI_COMM_CREATE(comm, group, newcomm) IN comm коммуникатор (дескриптор) IN group группа, являющаяся подмножеством группы comm (де- скриптор) OUT newcomm новый коммуникатор (дескриптор) int MPI_Comm_create(MPI_Comm comm, MPI_Group group, MPI_Comm *newcomm) MPI_COMM_CREATE(COMM, GROUP, NEWCOMM, IERROR) INTEGER COMM, GROUP, NEWCOMM, IERROR MPI::Intracomm MPI::Intracomm::Create(const MPI::Group& croup) const Эта функция создает новый коммуникатор newcomm с коммуни- кационной группой, определенной аргументом group и новым кон- текстом. Из comm в newcomm не передается никакой кэшированной информации. Функция возвращает MPI_COMM_NULL для процес- сов, не входящих в group . Запрос неверен, если не все аргументы в group имеют одинаковое значение или если group не является под- множеством группы, связанной с comm . Заметим, что запрос должен быть выполнен всеми процессами в comm , даже если они не принад- лежат новой группе. MPI_COMM_SPLIT(comm, color, key, newcomm) IN comm коммуникатор (дескриптор) IN color управление созданием подмножества (целое) IN key управление назначением номеров целое) OUT newcomm новый коммуникатор (дескриптор) int MPI_Comm_split(MPI_Comm comm, int color, int key, MPI_Comm *newcomm) 153 MPI_COMM_SPLIT(COMM, COLOR, KEY, NEWCOMM, IERROR) INTEGER COMM, COLOR, KEY, NEWCOMM, IERROR MPI::Intracomm MPI::Intracomm::Split(int color, int key) const Эта функция делит группу, связанную с comm, на непересекаю- щиеся подгруппы по одной для каждого значения color . Каждая под- группа содержит все процессы одного цвета. В пределах каждой под- группы процессы пронумерованы в порядке, определенном значением аргумента key , со связями, разделенными согласно их номеру в старой группе. Для каждой подгруппы создается новый коммуникатор и возвра- щается в аргументе newcomm . Процесс может иметь значение цвета MPI_UNDEFINED , тогда переменная newcomm возвращает значение MPI_COMM_NULL . Это коллективная операция, но каждому про- цессу разрешается иметь различные значения для color и key Обращение к MPI_COMM_CREATE (сomm, group, newcomm) эквивалентно обращению к MPI_COMM_SPLIT (comm, color, key, newcomm), где все члены group имеют color =0 и key = номеру в group , и все процессы, которые не являются членами group , имеют color = MPI_UNDEFINED Функция MPI_COMM_SPLIT допускает более общее разделение группы на одну или несколько подгрупп с необязательным переупо- рядочением. Этот запрос используют только интра-коммуникаторы. Значение color должно быть неотрицательно. 5.4.3. Деструкторы коммуникаторов MPI_COMM_FREE(comm) INOUT comm удаляемый коммуникатор (handle) int MPI_Comm_free(MPI_Comm *comm) MPI_COMM_FREE(COMM, IERROR) INTEGER COMM, IERROR void MPI::Comm:Free() Эта коллективная операция маркирует коммуникационный объект для удаления. Дескриптор устанавливается в MPI_COMM_NULL Любые ждущие операции, которые используют этот коммуникатор, будут завершаться нормально; объект фактически удаляется только в том случае, если не имеется никаких других активных ссылок на него. 154 5.5 . ПРИМЕРЫ Пример 5.1. main(int argc, char **argv) { int me, count, count2; void *send_buf, *recv_buf, *send_buf2, *recv_buf2; MPI_Group MPI_GROUP_WORLD, grprem; MPI_Comm commslave; static int ranks[ ] = {0}; MPI_Init(&argc, &argv); MPI_Comm_group(MPI_COMM_WORLD,&MPI_GROUP_WORLD); MPI_Comm_rank(MPI_COMM_WORLD, &me); /* локально */ MPI_Group_excl(MPI_GROUP_WORLD, 1, ranks, &grprem); /* локально */ MPI_Comm_create(MPI_COMM_WORLD, grprem, &commslave); if(me != 0) { … /* вычисления на подчиненном процессе */ MPI_Reduce(send_buf,recv_buff,count, MPI_INT, MPI_SUM, 1, commslave); } /* процесс 0 останавливается немедленно после выполнения этого reduce, другие процессы – позже... */ MPI_Reduce(send_buf2, recv_buff2, count2, MPI_INT, MPI_SUM, 0, MPI_COMM_WORLD); MPI_Comm_free(&commslave); MPI_Group_free(&MPI_GROUP_WORLD); MPI_Group_free(&grprem); MPI_Finalize(); } Этот пример иллюстрирует, как из исходной группы создается группа, содержащая все процессы, кроме процесса 0, затем, как фор- мируется коммуникатор ( commslave ) для новой группы. Новый ком- муникатор используется в коллективном обмене, и все процессы вы- полняются в контексте MPI_COMM_WORLD . Пример иллюстриру- ет, как два коммуникатора (которые обязательно имеют различные контексты) защищают обмен. Это означает, что обмен в commslave изолирован от обмена в MPI_COMM_WORLD, и наоборот. 155 Пример 5.2. Следующий пример иллюстрирует "безопасное" выпол- нение парного и коллективного обменов в одном коммуникаторе. #define TAG_ARBITRARY 12345 #define SOME_COUNT 50 main(int argc, char **argv) { int me; MPI_Request request[2]; MPI_Status status[2]; MPI_Group MPI_GROUP_WORLD, subgroup; int ranks[] = {2, 4, 6, 8}; MPI_Comm the_comm; MPI_Init(&argc, &argv); MPI_Comm_group(MPI_COMM_WORLD,&MPI_GROUP_WORLD); MPI_Group_incl(MPI_GROUP_WORLD,4,ranks, &subgroup); /*локально */ MPI_Group_rank(subgroup, &me); /* локально */ MPI_Comm_create(MPI_COMM_WORLD, subgroup, &the_comm); /* парный обмен */ if(me != MPI_UNDEFINED) { MPI_Irecv(buff1, count, MPI_DOUBLE, MPI_ANY_SOURCE, TAG_ARBITRARY, the_comm, request); MPI_Isend(buff2, count, MPI_DOUBLE, (me+1)%4, TAG_ARBITRARY, the_comm, request+1); } /* коллективная операция */ for(i = 0; i < SOME_COUNT, i++) MPI_Reduce(..., the_comm); MPI_Waitall(2, request, status); MPI_Comm_free(t&he_comm); MPI_Group_free(&MPI_GROUP_WORLD); MPI_Group_free(&subgroup); MPI_Finalize(); } КОНТРОЛЬНЫЕ ВОПРОСЫ И ЗАДАНИЯ К ГЛАВЕ 5 Контрольные вопросы к 5.1 1. Какие преимущества получает пользователь, использующий параллельные библиотеки? 2. Перечислите проблемы при написании параллельных библиотек. 3. Какие специфические структуры введены в MPI, необходимые для создания и использования параллельных библиотек? 4. В чем различие между группой процессов и коммуникатором? 5. Могут ли общаться процессы, принадлежащие разным коммуникаторам? 6. Что такое виртуальная топология? 156 Контрольные вопросы к 5.2 1. Можно ли ввести собственную нумерацию процессов в группе, например: 2,4,6,8,…? 2. Какая предопределенная константа является группой без членов? 3. В какой момент выполнения приложения определяется начальный коммуни- катор MPI_COMM_WORLD? 4. MPI_COMM_WORLD является интер или интра-коммуникатором? 5. Можно ли удалить коммуникатор MPI_COMM_WORLD в течение времени существования процесса? Контрольные вопросы к 5.3 1. Функции управления группой являются локальными или коллективными? 2. Что возвращает функция MPI_Group_rank, если процесс, в котором произво- дится вызов этой функции, не является членом этой группы? 3. Как определить номер процесса в группе, зная его номер в группе, соответст- вующей коммуникатору MPI_COMM_WORLD? 4. Перечислите три возможных варианта результата, которые можно получить после вызова функции MPI_Group_compare. 5. Функции-конструкторы групп являются локальными? 6. Что такое базовая группа? Приведите пример базовой группы. 7. Можно ли определить в каждом процессе приложения собственную группу процессов? 8. Какая функция позволяет определить группу какого-либо коммуникатора? 9. Можно ли определить группу, которая не включает в себя процесс, ее соз- дающий? 10. Перечислите операции над группами процессов, определенные для создания новой группы. Контрольные вопросы к 5.4 1. Можно ли изменить число процессов приложения после инициализации MPI? 2. Могут ли быть строго вложенными множества процессов, определяющие раз- личные коммуникаторы? 3. Должны ли быть непересекающимися множества процессов, определяющие различные коммуникаторы? 4. Должны ли множества процессов, определяющие различные коммуникаторы, состоять более чем из одного процесса? 5. Определены ли в каждой программе множества процессов, задающие различ- ные коммуникаторы в количестве большем, чем 2? 6. Функции доступа к коммуникаторам локальные или коллективные? 7. В чем сходство и различие использования функций MPI_Group_size и MPI_Comm_size, MPI_Group_rank и MPI_Com_rank, MPI_Group_compare и MPI_Com_compare? 8. Функции создания коммуникаторов локальные или коллективные? 9. Какой коммуникатор создает MPI_Comm_dup? 157 10. Какой коммуникатор создает функция MPI_Comm_create, если она вызывает- ся в процессе, не входящем в коммуникационную группу? 11. Сколько коммуникаторов создает MPI_Comm_split? Контрольные вопросы к 5.5 1. В каком процессе находится результат коллективной операции MPI_Reduce в примере 5.1, которая выполняется в новом коммуникаторе commslave? 2. Объясните необходимость использования проверки me!=MPI_UNDEFINED в примере 5.2. В каком случае процесс получает номер MPI_UNDEFINED? 3. Сколько процессов и какие входят в коммуникатор the_comm в примере 5.2? 4. Для какой цели в примере 5.2 приведен цикл, в котором MPI_Reduce повторя- ется много раз? 5. По какой схеме осуществляется обмен данными в примере 5.2? Задания для самостоятельной работы 5.1 . Организуйте передачу данных внутри коммуникатора, который создан на основании группы, созданной из произвольного числа процессов, заданных пользователем. Например, если 10 процессов в MPI_COMM_WORLD, то создайте группу из 2,3,6,8,9 процессов. 5.2. Постройте ввод-вывод по принципу master/slave. Главный процесс дол- жен принимать сообщения от подчиненных и печатать их в порядке нумерации (сначала 0, затем 1 и так далее). Подчиненные должны посылать каждый по 2 со- общения мастеру. Например, сообщения: Hello from slave 3 Goodbye from slave 3 (с соответствующими сообщениями для каждого подчиненного процесса). Для решения разделите процессы из MPI_COMM_WORLD на два коммуникатора: один процесс в качестве главного и остальные процессы – подчиненные. Исполь- зуйте новый коммуникатор для подчиненных процессов для того, чтобы полу- чить номер подчиненного процесса в его коммуникаторе. Подчиненные процессы могут также выполнять любые вычисления. 5.3. Выполните задание 5.2, изменив код мастера, чтобы он позволял прини- мать три типа сообщений от подчиненных процессов: упорядоченный вывод (та- кой же, как и в примере 1); неупорядоченный вывод (как если бы каждый подчи- ненный процесс печатал непосредственно); сообщение о выходе. Мастер продол- жает получать сообщения до тех пор, пока он не получит сообщения о выходе от всех подчиненных процессов. Для простоты программирования пусть каждый подчиненный процесс посылает сообщения: Hello from slave 3 Goodbye from slave 3 в упорядоченном выходном режиме и I'm exiting (3) в неупорядоченном режиме. 5.4. Напишите программу вычисления числа π методом Монте-Карло. Суть метода в следующем. Если радиус круга равен 1, тогда площадь круга равна π, а площадь квадрата вокруг круга равна 4. Следовательно, отношение площади кру- 158 га к площади квадрата равно π/4. Если теперь случайным образом генерировать точки в пределах контура квадрата, то отношение числа точек, попавших в круг, к общему количеству сгенерированных точек даст величину π/4. Сгенерированная точка находится в круге, если ее координаты соответствуют выражению x 2 + y 2 <1. Для генерации случайных чисел создайте отдельный процесс, который будет рас- сылать эти числа другим процессам. Поскольку другие процессы должны будут выполнить коллективные операции, в которых не участвует этот процесс, необхо- димо определить коммуникатор, чья группа не включает генерацию случайных чисел. 5.5. Пусть имеем n процессов, где n – произвольно. Создайте два коммуника- тора: отдельно из процессов с четными и нечетными номерами. Осуществите пе- редачу данных по кольцу внутри каждого коммуникатора. 5.6. Пусть количество процессов n=l*m. Тогда процессы можно представить решеткой: l – строк и m столбцов. Создайте коммуникаторы для каждой строки и каждого столбца решетки. Осуществите передачу данных по кольцу внутри каж- дого коммуникатора. |