Вычислительный центр им. А.А. Дородницына РАН    

Раздел виртуального курса
Параллельное программирование в интерфейсе MPI


MPI попарный обмен сообщениями I


Содержание

1.     Обзор

2.     Блокирующее поведение

2.1 Способы коммуникации
2.1.1 Блокирующая синхронная отправка
2.1.2 Блокирующая отправка по готовности
2.1.3 Блокирующая буферизованная отправка
2.1.4 Блокирующая стандартная отправка
2.1.5 Блокирующие отправка и получение
2.2 Выводы: Способы

3.     Неблокирующее поведение

3.1 Синтаксис неблокирующих вызовов
3.2 Пример: Неблокирующая стандартная отправка
3.3 Пример: Неблокирующая стандартная отправка, большое сообщение
3.4 Выводы: неблокирующие вызовы

4.     Рекомендации по программированию

Литература Лабораторная работа Вопросы

1. Обзор

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

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

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

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

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

Неблокирующий вызов отделяет коммуникацию от вычисления. Неблокирующий вызов гарантирует, что прерывание будет сгенерировано, когда сообщение готово к выполнению, тем самым, позволяя вернуться назад к вычислительно-ориентированной обработке.


2. Блокирующее поведение

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

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

int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)

Параметры:

buf √ начало буфера, содержащего данные для отправки. Для C это √ адрес.

сount √ количество элементов для отправки (не байт)

вatatype - тип данных

dest √ ранг процесса, который является назначением сообщения

tag √ произвольное число, которое можно использовать для того, чтобы отличать данное сообщения от других

comm √ коммуникатор

Подобно MPI_Send, MPI_Recv является блокирующей. Это означает, что вызов не возвращает управление в программу, до тех пор, пока все получаемые данные не будут записаны в переменные, которые были определены программистом в списке параметров. В силу этого возможно обращаться к данным после вызова и можно быть уверенным, что эти данные существуют. (Вообще говоря, существуют неблокирующие получения, в которых это не имеет места.)

int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int tag, MPI_Comm comm, MPI_Status *status)

Параметры:

buf √ начало буфера для хранения приходящих данных. Для C это √ адрес.

count √ количество элементов (не байт) в буфере получения

datatype √ тип данных

source √ источник, то есть ранг процесса, из которого данные будут приняты (источник отправления может быть назначен любым (джокером √ wildcard), если определить параметр MPI_ANY_SOURCE)

tag √ тег, то есть произвольное число, которое можно использовать для отличия данного сообщения от других (тег принимаемого сообщения может быть любым (джокером √ wildcard), если определить параметр MPI_ANY_TAG)

comm √ коммуникатор

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

2.1 Способы коммуникации

Способ коммуникации выбирается при определении функции отправки. Существуют четыре функции блокирующей отправки и четыре функции неблокирующей отправки, соответствующие четырем способам коммуникации. Функция получения не определяет способ коммуникации √ она просто является блокирующей или неблокирующей.

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

Способ коммуникации

Блокирующие функции

Неблокирующие функции

Синхронный

MPI_Ssend

MPI_Issend

По готовности

MPI_Rsend

MPI_Irsend

Буферизованный

MPI_Bsend

MPI_Ibsend

Стандартный

MPI_Send

MPI_Isend

 

MPI_Recv

MPI_Irecv

 

MPI_Sendrecv

 

 

MPI_Sendrecv_replace

 

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

2.1.1 Блокирующая синхронная отправка

На диаграмме, приведенной ниже, время возрастает слева направо. Жирная горизонтальная линия, помеченная S, обозначает ось времени исполнения для задачи отправки (на одном узле), а жирная пунктирная линия, помеченная R, обозначает ось времени исполнения для задачи получения (на втором узле). Разрывы в этих линиях представляют прерывания, обусловленные событием √ передача сообщения.

[Try This]Флэш-анимация

Когда блокирующая синхронная отправка MPI_Ssend исполняется, задача отправки отправляет задаче получения сообщение "готова к отправке". Когда задача получателя исполняет вызов получения, она посылает сообщение "готова к получению". Затем данные передаются.

Существуют два источника накладок (overhead) в передаче сообщений. Системная накладка вызывается копированием данных сообщения из буфера сообщения отправителя и копированием данных из сети в буфер сообщения получателя.

Синхронизационная накладка равна времени, потраченному на ожидании другой задачи. На вышеприведенном рисунке отправитель должен ждать исполнение события получения и наступление встречи, перед тем как сообщение может быть передано. Получатель также подвержен некоторой синхронизационной накладке при ожидании завершения встречи. Неудивительно, что синхронизационная накладка может быть значительной в синхронном способе. Как мы увидим, другие способы используют различные стратегии для сокращения этой накладки.

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

Можно надеяться, что если работа соответствующим образом сбалансирована по загрузке, синхронизационная накладка будет минимальна как для задачи отправления, так и для задачи получения. Это не всегда выполняется. Если нет других причин для отсутствия синхронизации, то системные службы, которые выполняются в неизвестные моменты времени на различных узлах, вызовут несинхронизированные задержки. Конечно, можно просто часто вызывать функцию MPI_Barrier, чтобы сохранить задачи синхронными. К сожалению, этот вызов сам по себе испытывает синхронизационную накладку и не гарантирует, что задачи будут синхронными после вызова. Таким образом, вызов этой функции почти всегда является потерей времени. (MPI_Barrier блокирует вызовы, пока все члены группы не вызовут его.)


2.1.2 Блокирующая отправка по готовности

[Try This]Флэш-анимация

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

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

Указанный способ не следует использовать кроме тех случаев, когда пользователь уверен, что соответствующее уведомление о готовности получения послано.


2.1.3 Блокирующая буферизованная отправка

[Try This]Флэш-анимация

Блокирующая буферизованная отправка MPI_Bsend копирует данные из буфера сообщения в буфер, предложенный пользователем, и затем возвращает данные обратно. Поэтому отправляющая задача может выполнять вычисления, которые модифицируют оригинальный буфер сообщения, зная, что эти модификации не будут отражены в данных, которые были действительно отправлены. Данные будут скопированы из предложенного пользователем буфера в сеть, когда будет получено уведомление "готова получить".

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

Другой выгодой для пользователя является возможность обеспечить то количество буферного пространства для исходящих сообщений, в котором программа нуждается. С другой стороны, пользователь ответственен за управление и прикрепление этого буферного пространства. Буферизованный способ отправки, который требует больше буферного пространства, чем имеется в наличии, сгенерирует ошибку, и, по умолчанию, программа завершит работу.

Буферное управление

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

Это пространство памяти должно быть идентифицировано, как предложенный пользователем буфер посредством вызова MPI_Buffer_attach. Когда в этом пространстве больше нет нужды, оно может быть отделено камандной MPI_Buffer_detach. В каждый момент времени может быть активным только один предложенный пользователем буфер сообщения, в котором записываются многочисленные сообщения. Система сохраняет данные о том, когда сообщения, в конце концов, покидают буфер, и использует буферное пространство заново. Безопасность программы не должна зависеть от этого обстоятельства.


2.1.4 Блокирующая стандартная отправка

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

Размер сообщения меньше порогового значения

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

[Try This]Флэш анимация

В этом случае блокирующая стандартная отправка MPI_Send копирует сообщение из сети в системный буфер узла получателя. Стандартная отправка затем возвращается, и отправляющая задача может продолжать вычисление. Системный буфер прикрепляется, когда программа стартует √ пользователю нет нужды управлять этим процессом каким-либо способом. На задачу выделяется один системный буфер, который будет содержать множественные сообщения. Сообщение будет скопировано из системного буфера в задачу получения, когда вызов получения исполняется.

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

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

Размер сообщения больше порогового значения

Когда размер сообщения больше порогового значения, поведение блокирующей стандартной отправки MPI_Send, по-существу, то же самое, как и в случае синхронного способа.

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

Итак, было рассмотрено поведение системы в случае всех четырех способов коммуникации для блокирующих отправлений.


2.1.5 Блокирующие отправка и получение

Операции отправки и получения могут быть скомбинированы в один вызов. MPI_Sendrecv осуществляет блокирующие отправку и получение, в которых буферы для отправки и получения должны быть разъединены. MPI_Sendrecv_replace также осуществляет блокирующие отправку и получение. Однако, в этом случае существует только один буфер вместо двух, поскольку получаемое сообщение переписывает отправляемое. Для этих вызовов:

 


2.2 Выводы: Способы

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

Способ по готовности имеет наименьшую суммарную накладку. Он действительно не требует встречи отправителя и получателя (подобно синхронизированному способу) или дополнительного копирования в буфер (подобно буферизованному или стандартному способу). Тем не менее, получение должно предшествовать отправке. Этот способ не всегда подходит для всех сообщений.

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

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


3. Неблокирующее поведение

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

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

Программист может выбрать блокировку до тех пор, пока буфер сообщения нельзя будет безопасно использовать. Блокировку можно установить посредством вызова MPI_Wait и его вариантов или же это можно сделать, возвращая текущий статус коммуникации с помощью MPI_Test и его вариантов.

Различные варианты вызовов Wait и Test позволяют проверить статус определенного сообщения, а также проверить либо все, либо любое, либо некоторые сообщения из списка.

Интуитивно ясно, почему необходимо проверить статус неблокирующего получения: очевидно, не рационально считывать сообщение, пока нет уверенности, что это сообщение прибыло. Менее очевидно, почему необходимо проверять статус неблокирующего отправления. На самом деле это действительно необходимо, если имеется цикл, который повторно заполняет буфер сообщения и отправляет сообщение. Нельзя записать что-нибудь новое в буфер, пока нет уверенности в том, что предыдущее сообщение успешно скопировано из буфера. Если даже буфер отправки не используется повторно, выгодно завершить коммуникацию, так как это освобождает системные ресурсы.


3.1 Синтаксис неблокирующих вызовов

Неблокирующие вызовы имеют тот же синтаксис, что и блокирующие, за исключением двух исключений:

  1. Каждый вызов отправки помечается индексом "I", который следует сразу за знаком "_".
  2. Последний аргумент есть способ доступа к скрытому объекту запроса, который содержит информацию о сообщении (т.е. его статус).

Например, стандартная неблокирующая отправка и соответствующий вызов Wait выглядят как:

MPI_Isend (buf,count,dtype,dest,tag,comm,request)
MPI_Wait (request, status)

Аналогично, неблокирующий вызов получения есть MPI_Irecv.

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


3.2 Пример: Неблокирующая стандартная отправка

Итак, было рассмотрено блокирующее поведение для каждого способа коммуникации. Теперь обсудим неблокирующее поведение для стандартного способа коммуникации. Поведение других способов коммуникации может быть получено из этих двух способов.

Следующий рисунок демонстрирует использование обоих вызовов: неблокирующей стандартной отправки MPI_Isend и неблокирующего получения MPI_Irecv. Как и раньше, отправка стандартным способом будет выполняться по-разному в зависимости от размера сообщения. Следующий рисунок демонстрирует это поведение для размера сообщения, который не превышает порогового значения.

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

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

Системная накладка не отличается существенно от накладки при блокирующих вызовах отправки и получения. На оборудовании, где для передачи данных необходим ЦПУ, вычисления будут прерваны как на узле отправки, так и на узле получения, чтобы переправить сообщение. Момент времени, когда прерывание случается, не должен как-то особо влиять на выполняемую программу. Даже для архитектур, которые позволяют одновременную передачу данных и вычисления, тот факт, что этот эффект наблюдается только в случае малых сообщений, означает, что не стоит ожидать большой разницы в эффективности работы.

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

Преимущество неблокирующего получения перед блокирующим может быть значительным, если получение послано перед отправкой. Задача может продолжить вычисления до тех пор, пока не посылается Wait, вместо того, чтобы находиться в бездействии. (Желательно послать отправку любого типа до тех пор, пока она не совпадет с получением так, чтобы по прибытии сообщения, оно непосредственно попало в буфер программы, а не в системный буфер.) Значит, если послать MPI_Irecv как можно раньше, то это снизит синхронизационную накладку.

Неблокирующий вызов гарантирует, что ситуация тупика √ когда оба процессора ожидают друг друга √ не возникнет. Для этого необходимо убедиться, что все вызовы Wait должны быть посланы за всеми вызовами Send и Receive для того, чтобы коммуникация была завершена.


3.3 Пример: Неблокирующая стандартная отправка для случая сообщения большого размера

Случай неблокирующей стандартной отправки MPI_Isend для сообщения, размер которого превышает пороговое значение:

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

Далее, неблокирующее получение MPI_Irecv сократит синхронизационную накладку на принимающей задаче для случая, в котором получение послано первым. Существует также выгода в использовании неблокирующего получения, в случае, если отправка послана первой. Рассмотрим, как рисунок изменится, в случае, если блокирующее получение было послано. В типичной ситуации блокирующие получения посылаются непосредственно перед тем, как данные сообщения должны быть использованы (чтобы выделить максимальное время для завершения коммуникации). Таким образом, блокирующее получение было бы послано вместо MPI_Wait. Это задержало бы синхронизацию с вызовом отправки до этой более поздней точки в программе и таким образом увеличило бы синхронизационную накладку на отправляющей задаче.


3.4 Выводы: неблокирующие вызовы

          Преимущество неблокирующих вызовов

         Помогает избегать тупиков (deadlock)

Неблокирующие коммуникации помогают избежать ситуации, в которой процессы ожидают одного и того же ресурса или друг друга. Ситуации тупиков подробно рассмотрены в MPI попарный обмен II.

         Уменьшает синхронизационную накладку

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

         Сокращение системной накладки (на некоторых системах)

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

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

         Советы по применению неблокирующих вызовов

        Предпочтительно неблокирующие отправки посылать настолько рано, насколько это возможно и делать их ожидание как можно более долгим

Некоторое дополнительные затраты времени на программирвание требуются в случае неблокирующих вызовов, чтобы протестировать завершение коммуникации. Лучше всего посылать неблокирующие отправки настолько рано, насколько это возможно и ждать до их завершения настолько долго, насколько это возможно. ⌠Настолько рано, насколько это возможно■ означает, что данные в буфере, которые будут быть посланы, не должны содержать ошибок и принимающий буфер должен быть доступен. ⌠Настолько долго, насколько это возможно■ означает точку, в которой буфер отправителя будет переписан, или  точку, в которой полученные данные необходимы для вычислений.

 

            Необходимо избегать записи в буфер отсылки между MPI_Isend и MPI_Wait, а также

            считывания и записи в буфер получения между MPI_Irecv и MPI_Wait.

 

Необходимо, чтобы была обеспечена возможность безопасно считывать буфер отправки после того, как отправка послана. При этом ничего не должно быть записано в этот буфер до тех пор, пока статус не будет проверен, чтобы гарантировать, что первоначальное сообщение отослано. В противном случае, содержимое первоначального сообщения может быть затерто. Между посылкой неблокирующего получения и определением того, что сообщение получено, НЕ должно производиться какого-либо пользовательского чтения или записывания в буфер получения. Чтение может давать либо старые данные или новые (полученные) данные сообщения. Запись может переписать недавно прибывшее сообщение.

 

4. Рекомендации по программированию

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

        Блокирующие вызовы могут потребоваться, если программист хочет синхронизовать задачи. Также, если программа требует, чтобы за неблокирующим вызовом немедленно следовал Wait, то намного эффективнее использовать блокирующий вызов. Если используются блокирующие вызовы, то может быть выгодно сначала использовать синхронный способ, а затем переключиться на стандартный способ. Тестирование в синхронном способе гарантирует, что программа не зависит от наличия достаточного системного буферного пространства.

        Следующим шагом является анализ кода и оценка эффективности его работы. Если неблокирующие получения посланы рано, значительно ранее соответствующих отправок, будет выгодно использовать способ по готовности. Чтобы еще усилить безопасность, получающая задача должна, вероятно, извещать отправителя после того, как получения посланы. После получения уведомления, отправитель может выполнить отправки.

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


Литература

Cornell Theory Center MPI Point to Point Communication I

Богач╦в К.Ю. Основы параллельного программирования. -- М.: БИНОМ. Лаборатория знаний, 2003. -- 342 с.

Немнюгин С.А., Стесик О.Л. Параллельное программирование для многопроцессорных вычислительных систем. -- СПб.: БХВ-Петербург, 2002. -- 400 с.: ил.

MPI Home Page at Argonne National Labs http://www.mcs.anl.gov/mpi

Message Passing Interface Forum (1995) MPI: A Message Passing Interface Standard. June 12, 1995. Доступен на русском языке в pdf-формате из сайта http://www.cluster.bsu.by/MPI_ALL.htm


[Quiz]Вопросы для проверки усвоения материала

[Exercise]Лабораторная работа


 

 

╘ 2005 Вычислительный центр им. А.А.Дородницына Все права защищены.
Прочтите наше Copyright руководство.