3.3. Неблокирующие коммуникационные операции
Использование неблокирующих коммуникационных операций повышает безопасность с точки зрения возникновения тупиковых ситуаций, а также может увеличить скорость работы программы за счет совмещения выполнения вычислительных и коммуникационных операций. Эти задачи решаются разделением коммуникационных операций на две стадии: инициирование операции и проверку завершения операции.
Неблокирующие операции используют специальный скрытый (opaque) объект "запрос обмена" (request) для связи между функциями обмена и функциями опроса их завершения. Для прикладных программ доступ к этому объекту возможен только через вызовы MPI-функций. Если операция обмена завершена, подпрограмма проверки снимает "запрос обмена", устанавливая его в значение MPI_REQUEST_NULL. Снять запрос без ожидания завершения операции можно подпрограммой MPI_Request_free.
Функция передачи сообщения без блокировки MPI_Isend
IN | buf | - адрес начала расположения передаваемых данных; |
IN | count | - число посылаемых элементов; |
IN | datatype | - тип посылаемых элементов; |
IN | dest | - номер процесса-получателя; |
IN | tag | - идентификатор сообщения; |
IN | comm | - коммуникатор; |
OUT | request | - "запрос обмена". |
Возврат из подпрограммы происходит немедленно (immediate), без ожидания окончания передачи данных. Этим объясняется префикс I в именах функций. Поэтому переменную buf повторно использовать нельзя до тех пор, пока не будет погашен "запрос обмена". Это можно сделать с помощью подпрограмм MPI_Wait или MPI_Test, передав им параметр request.
Функция приема сообщения без блокировки MPI_Irecv
OUT | buf | - адрес для принимаемых данных; |
IN | count | - максимальное число принимаемых элементов; |
IN | datatype | - тип элементов принимаемого сообщения; |
IN | source | - номер процесса-отправителя; |
IN | tag | - идентификатор сообщения; |
IN | comm | - коммуникатор; |
OUT | request | - "запрос обмена". |
Возврат из подпрограммы происходит немедленно, без ожидания окончания приема данных. Определить момент окончания приема можно с помощью подпрограмм MPI_Wait или MPI_Test с соответствующим параметром request.
Как и в блокирующих операциях часто возникает необходимость опроса параметров полученного сообщения без его фактического чтения. Это делается с помощью функции MPI_Iprobe.
Неблокирующая функция чтения параметров полученного сообщения MPI_Iprobe
IN | source | - номер процесса-отправителя; |
IN | tag | - идентификатор сообщения; |
IN | comm | - коммуникатор; |
OUT | flag | - признак завершенности операции; |
OUT | status | - атрибуты опрошенного сообщения. |
Если flag=true, то операция завершилась, и в переменной status находятся атрибуты этого сообщения.
Воспользоваться результатом неблокирующей коммуникационной операции или повторно использовать ее параметры можно только после ее полного завершения. Имеется два типа функций завершения неблокирующих операций:
Функция ожидания завершения неблокирующей операции MPI_Wait
INOUT | request | - "запрос обмена"; |
OUT | status | - атрибуты сообщения. |
Это нелокальная блокирующая операция. Возврат происходит после завершения операции, связанной с запросом request. В параметре status возвращается информация о законченной операции.
Функция проверки завершения неблокирующей операции MPI_Test
INOUT | request | - | "запрос обмена"; |
OUT | flag | - | признак завершенности проверяемой операции; |
OUT | status | - | атрибуты сообщения, если операция завершилась. |
Это локальная неблокирующая операция. Если связанная с запросом request операция завершена, возвращается flag = true, а status содержит информацию о завершенной операции. Если проверяемая операция не завершена, возвращается flag = false, а значение status в этом случае не определено.
Рассмотрим пример использования неблокирующих операций и функции MPI_Wait.
CALL MPI_COMM_RANK(comm, rank, ierr) IF (rank.EQ.0) THEN CALL MPI_ISEND(a(1), 10, MPI_REAL, 1, tag, comm, request, ierr) **** Выполнение вычислений во время передачи сообщения **** CALL MPI_WAIT(request, status, ierr) ELSE CALL MPI_IRECV(a(1), 15, MPI_REAL, 0, tag, comm, request, ierr) **** Выполнение вычислений во время приема сообщения **** CALL MPI_WAIT(request, status, ierr) END IF
Функция снятия запроса без ожидания завершения неблокирующей операции MPI_Request_free
INOUT request - запрос связи.
Параметр request устанавливается в значение MPI_REQUEST_NULL. Связанная с этим запросом операция не прерывается, однако проверить ее завершение с помощью MPI_Wait или MPI_Test уже нельзя. Для прерывания коммуникационной операции следует использовать функцию MPI_Cancel(MPI_Request *request).
В MPI имеется набор подпрограмм для одновременной проверки на завершение нескольких операций. Без подробного обсуждения приведем их перечень (таблица 3.3).
Выполняемая проверка | Функции ожидания (блокирующие) | Функции проверки (неблокирующие) |
Завершились все операции | MPI_Waitall | MPI_Testall |
Завершилась по крайней мере одна операция | MPI_Waitany | MPI_Testany |
Завершилась одна из списка проверяемых | MPI_Waitsome | MPI_Testsome |
Кроме того, MPI позволяет для неблокирующих операций формировать целые пакеты запросов на коммуникационные операции MPI_Send_init и MPI_Recv_init, которые запускаются функциями MPI_Start или MPI_Startall. Проверка на завершение выполнения производится обычными средствами с помощью функций семейства WAIT и TEST.