Организация неблокирующих обменов данными между процессами

Лекция 3,4. MP I (продолжение)

Подготовка к запуску параллельных программ

 

Это, собственно, справочный материал по основным и обязательным функциям, которые мы с вами без всяких объяснений использовали в наших примерах.

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

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

 

Синтаксис функции MPI_INIT представлен ниже.

MPI_INIT()

int MPI_Init(int *argc, char ***argv)

 

MPI_INIT(IERROR)

NTEGER IERROR

 

void Init(int& argc, char**& argv)

void Init()

Эта процедура должна быть вызвана прежде, чем будет вызвана какая - либо другая MPI подпрограмма (кроме MPI_INITIALIZED). Она должна быть вызвана всего один раз; последующие вызовы неверны (см. MPI_INITIALIZED). Все MPI программы должны содержать вызов MPI_INIT. Версия для ANSI Си принимает argc и argv, которые являются аргументами к main:

 

int main(argc, argv)

int argc;

char **argv;

{

MPI_Init(&argc, &argv);

 

/* анализ аргументов */

/* головная программа */

 

MPI_Finalize(); /* смотри ниже */

}

Версия для языка ФОРТРАН содержит только IERROR.

 

Реализация MPI не требует, чтобы аргументы в вызове для Си были аргументами main.

 

Объяснение: MPI_INIT может использовать командную строку аргументов для инициализации среды MPI. Они передаются по ссылке, чтобы позволить реализации MPI обеспечить их в среде, где аргументы командной строки не предусмотрены для main.[]

 

Синтаксис функции MPI_FINALIZE представлен ниже.

MPI_FINALIZE()

int MPI_Finalize(void)

 

MPI_FINALIZE(IERROR)

INTEGER IERROR

 

void Finalize()

Эта процедура очищает все состояния MPI. Никакая другая процедура MPI (даже MPI_INIT) не может быть вызвана после выполнения этой процедуры. Пользователь обязан гарантировать, что все незаконченные обмены будут завершены прежде, чем будет вызвана MPI_FINALIZE.

 

Синтаксис функции MPI_INITIALIZED представлен ниже.

MPI_INITIALIZED(flag)

OUT flag параметр flag принимает значение true, если MPI_INIT была вызвана и false в противном случае.      

int MPI_Initialized(int *flag)

 

MPI_INITIALIZED(FLAG, IERROR)

LOGICAL FLAG

INTEGER IERROR

 

bool MPI::Is_initialized()

 

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

MPI_INIT. Это единственная процедура, которая может быть вызвана перед MPI_INIT.

 

Синтаксис функции MPI_ABORT представлен ниже.

MPI_ABORT(comm, errorcode)

IN comm    коммуникатор прерываемой задачи     

IN errorcode код ошибки для возврата в среду исполнения        

int MPI_Abort(MPI_Comm comm, int errorcode)

 

MPI_ABORT(COMM, ERRORCODE, IERROR)

INTEGER COMM, ERRORCODE, IERROR

 

bool MPI::Is_finalized()

 

Процедура MPI_ABORT пробует наилучшим способом прервать выполнение всех задач в группе коммуникатора comm. Эта процедура не требует, чтобы исполнительная среда производила какие-либо действия с кодом ошибки. Однако, среда Unix или POSIX должна обрабатывать его как return errorcode из главной программы или abort (errorcode).

 

Реализация MPI должна определить поведение MPI_ABORT по крайней мере для коммуникатора MPI_COMM_WORLD. Реализация MPI может игнорировать аргумент comm и действовать, как если бы коммуникатором был MPI_COMM_WORLD.

 

Объяснение: Коммуникационный аргумент предусмотрен для будущих расщирений MPI в отношении среды исполнения, например, для динамического управления процессами. Это, в частности, позволяет (но не требует) реализации MPI прекратить действие подмножества

MPI_COMM_WORLD.[]


Пример – MPI_Abort() и MPI_Barrier() если есть ошибка в числе процессоров при запуске проги.

Контроль правильности выполнения функций.

Все функции MPI (кроме MPI_Wtime и MPI_Wtick) возвращают в качестве своего значения код завершения. При успешном выполнении функции возвращаемый код равен MPI_SUCCESS. Другие значения кода завершения свидетельствуют об обнаружении тех или иных ошибочных ситуаций в ходе выполнения функций. Для выяснения типа обнаруженной ошибки используются предопределенные именованные константы, среди которых:

  • MPI_ERR_BUFFER — неправильный указатель на буфер;
  • MPI_ERR_TRUNCATE — сообщение превышает размер приемного буфера;
  • MPI_ERR_COMM — неправильный коммуникатор;
  • MPI_ERR_RANK — неправильный ранг процесса и др.

Полный список констант для проверки кода завершения содержится в файле mpi.h. Однако, по умолчанию, возникновение любой ошибки во время выполнения функции MPI приводит к немедленному завершению параллельной программы. Для того чтобы иметь возможность проанализировать возвращаемый код завершения, необходимо воспользоваться предоставляемыми MPI функциями по созданию обработчиков ошибок и управлению ими.

Пример – проверка количества передаваемых и принятых данных «руками».

 

Как отделить работу узла root от рабочих узлов.

Итак, для разделения фрагментов кода между процессами обычно используется подход, примененный в рассмотренной ранее программе, – при помощи функции MPI_Comm_rank определяется ранг процесса, а затем в соответствии с рангом выделяются необходимые для процесса участки программного кода. Наличие в одной и той же программе фрагментов кода разных процессов также значительно усложняет понимание и, в целом, разработку MPI-программы. Как результат, можно рекомендовать при увеличении объема разрабатываемых программ выносить программный код разных процессов в отдельные программные модули (функции). Общая схема MPI-программы в этом случае будет иметь вид:

MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);

if ( ProcRank == 0 ) DoProcess0();

else if ( ProcRank == 1 ) DoProcess1();

else if ( ProcRank == 2 ) DoProcess2();

Во многих случаях, выполняемые действия являются отличающимися только для процесса с рангом 0. В этом случае общая схема MPI-программы принимает более простой вид:

MPI_Comm_rank(MPI_COMM_WORLD, &ProcRank);

if ( ProcRank == 0 ) DoManagerProcess();

else DoWorkerProcesses();     

Пример – обмен данных по кольцу

Организация неблокирующих обменов данными между процессами

 

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

MPI обеспечивает возможность неблокированного выполнения операций передачи данных между двумя процессами. Наименование неблокирующих аналогов образуется из названий соответствующих функций путем добавления префикса I (Immediate). Список параметров неблокирующих функций содержит обычный набор параметров исходных функций и один дополнительный параметр request с типом MPI_Request (в функции MPI_Irecv отсутствует также параметр status):

int MPI_Isend(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *request),

int MPI_Issend(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *request),

int MPI_Ibsend(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *request),

int MPI_Irsend(void *buf, int count, MPI_Datatype type, int dest, int tag, MPI_Comm comm, MPI_Request *request),

int MPI_Irecv(void *buf, int count, MPI_Datatype type, int source, int tag, MPI_Comm comm, MPI_Request *request).

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

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

int MPI_Test(MPI_Request *request, int *flag, MPI_status *status),

где

· request — дескриптор операции, определенный при вызове неблокирующей функции;

· flag — результат проверки (true, если операция завершена);

· status — результат выполнения операции обмена (только для завершенной операции).

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

MPI_Isend(buf, count, type, dest, tag, comm, &request);

ѕ

do {

 ѕ

 MPI_Test(&request, &flag, &status);

} while (!flag);

Если при выполнении неблокирующей операции окажется, что продолжение вычислений невозможно без получения передаваемых данных, то может быть использована блокирующая операция ожидания завершения операции:

int MPI_Wait(MPI_Request *request, MPI_status *status),

где

· request — дескриптор операции, определенный при вызове неблокирующей функции;

· status — результат выполнения операции обмена (только для завершенной операции).

Кроме рассмотренных, MPI содержит ряд дополнительных функций проверки и ожидания неблокирующих операций обмена:

· MPI_Testall — проверка завершения всех перечисленных операций обмена;

· MPI_Waitall — ожидание завершения всех операций обмена;

· MPI_Testany — проверка завершения хотя бы одной из перечисленных операций обмена;

· MPI_Waitany — ожидание завершения любой из перечисленных операций обмена;

· MPI_Testsome — проверка завершения каждой из перечисленных операций обмена;

· MPI_Waitsome — ожидание завершения хотя бы одной из перечисленных операций обмена и оценка состояния по всем операциям.

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


Дата добавления: 2021-03-18; просмотров: 72; Мы поможем в написании вашей работы!

Поделиться с друзьями:




Мы поможем в написании ваших работ!