PobedilRomanskogo / Введение в MPI
.pdfНеблокирующий прием
call MPI_IRECV(buf, cnt, source, tag, comm, req, err)
Все аргументы аналогичны MPI_RECV. За исключением нового выходного аргумента req типа integer, идентификатора асинхронного приема данных.
Возврат из подпрограммы происходит сразу после инициализации процесса приема без ожидания получения сообщения в буфере buf.
21
Завершение асинхронного обмена
call MPI_WAIT(req, stat, err) - ожидание завершения асинхронных процедур MPI_ISEND или MPI_IRECV, ассоциированных с идентификатором req. В случае приема, атрибуты и длину полученного сообщения можно определить с помощью выходного массива stat (см. слайд №16).
call MPI_WAITALL(cnt, reqs, stats,err)
integer :: cnt ! Число операций приема или передачи integer, dimension(cnt) :: reqs ! Массив идентификаторов
integer,dimension(cnt,MPI_STATUS_SIZE) :: stats ! Массив статусов
Выполнение процесса блокируется до тех пор, пока все операции обмена, ассоциированные с указанными идентификаторами, не будут завершены. Если во время одной или нескольких операций обмена возникли ошибки, то поле
ошибки в элементах массива stats будет установлено в |
22 |
|
соответствующее значение.
integer :: stats(MPI_STATUS_SIZE,99) ! Не больше 100 процессов integer :: reqs(99), err, tag = 1, nreq, rk, sz
real :: arr(99)
………
if(rk == 0) then do i = 1, sz-1
! 0-ой процесс получает все данные
call MPI_IRECV(arr(i),1,MPI_REAL,i,MPI_ANY_TAG,MPI_COMM_WORLD,& reqs(i),err)
enddo
nreq = sz-1 ! число запросов else
! Все остальные шлют данные в 0-ой массив
call MPI_ISEND(arr(rk),1,MPI_REAL,0,tag,MPI_COMM_WORLD,reqs(1),err) nreq = 1 ! число запросов
endif
!Проводим какие-то вычисления, не зависящие от arr
…………
!Проверяем статус посылок и приемов
call MPI_WAITALL(nreq,reqs,stats,err)
………
Во время выполнения не блокирующих обменов MPI, область памяти на процессе-отправителе, из которой выполняется передача данных, и
область памяти на процессе-получателе в которую будут записаны полученные данные не блокируются и доступны для любых операций.
Чтобы завершить неблокирующий обмен, используются MPI_WAIT / MPI_WAITALL (процедуры ожидания с блокировкой) или MPI_TEST / MPI_TESTALL (процедуры ожидания без блокировки).
Для определения структуры сообщения использовать: call MPI_IPROBE(source, tag, comm, flag, stat, err)
logical :: flag ! Выходной арг. показывает можно ли принять сообщение
Функции завершения обмена необходимы:
•для правильной работы MPI,
•для того, чтобы программист знал, что обмен завершен и можно использовать данные из буфера обмена.
24
Два в одном: объединенный обмен данными
call MPI_SENDRECV(sendbuf, sendcnt, sendtype, dest, sendtag, recvbuf, recvcnt, recvtype, source, recvtag, comm, stat, err)
sendbuf - буфера отправителя;
sendcnt - число элементов в буфере отправителя; sendtype - тип элементов в буфере отправителя; dest - номер процесса-получателя;
sendtag - тэг процесса-отправителя; recvbuf - приемный буфер (выходной арг.);
recvcnt - число элементов в приемном буфере; recvtype – тип элементов в приемном буфере; source - номер процесса-отправителя;
recvtag - тэг процесса-получателя; comm - коммуникатор;
stat - массива статус (выходной арг.) см. слайд №16.
MPI_SENDRECV - блокирующая передача и прием.
MPI_SENDRECV комбинирует в одном обращении посылку сообщения одному получателю и прием сообщения от другого отправителя. Получателем и отправителем может быть тот же самый процесс.
MPI_SENDRECV полезна для выполнения сдвига по цепочке процессов. Если для такого сдвига были использованы блокирующие приемы и передачи, тогда нужно корректно упорядочить эти приемы и передачи (например, четные процессы передают, затем принимают; нечетные процессы сначала принимают, затем передают), чтобы предупредить зависимости, которые могут привести к взаимной блокировке (deadlock). Если используется
MPI_SENDRECV, то MPI сама разрешает такие ситуации.
Сообщение, посланное операцией MPI_SENDRECV, можно получить стандартной подпрограммой приема или проверить MPI_PROBE. MPI_SENDRECV может получать сообщения, посланные обычной посылкой.
26
call MPI_SENDRECV_REPLACE(buf, cnt, datatype, dest, sendtag, source, recvtag, comm, stat, err)
MPI_SENDRECV_REPLACE - блокирующая передача и прием. Один и тоже буфер buf используется для отправки и получения данных: посланное сообщение замещается полученным.
Принимаемое сообщение не должно превышать по размеру отправляемое сообщение, а передаваемые и принимаемые данные должны быть одного типа.
MPI_SENDRECV_REPLACE также гарантировано не вызывает блокировок.
27
Взаимоблокировки (deadlock)
Процесс 0 |
Процесс 1 |
|
|
RECV из процесса 1 RECV из процесса 0
SEND в процесс 1 SEND в процесс 0
При таком обмене гарантированно получим deadlock. Так как RECV не вернут управление, пока не получат данные.
MPI_SENDRECV и MPI_SENRECV_REPLACE делают программу более устойчивой, т.к. они берут на себя заботу о deadlock’ах.
Процесс 0 |
Процесс 1 |
|
|
RECV из процесса 1 |
IRECV из процесса 0 |
|
|
SEND в процесс 1 |
SEND в процесс 0 |
|
WAIT |
|
|
IRECV
позволяет
избежать deadlock
28
Джокеры
В MPI определены специальные константы (джокеры). MPI резервирует для них отрицательные целые числа, в то время как реальные идентификаторы задач и сообщений лежат всегда в диапазоне от 0 до 32767.
Определены следующие джокеры: MPI_ANY_SOURCE – принимай от кого угодно (т.е. от любого процесса);
MPI_ANY_TAG – принимай, что угодно (т.е. с любым тэгом). MPI_PROC_NULL – несуществующий процесс.
Пользоваться джокерами следует с осторожностью,
потому что по ошибке таким вызовом MPI_RECV (и др.) можно получить сообщение, предназначенное другому процессу. В сложных программах рекомендуется
использовать джокеры только в MPI_PROBE, MPI_IPROBE.
29
call MPI_COMM_SIZE(MPI_COMM_WORLD, sz, err) call MPI_COMM_RANK(MPI_COMM_WORLD, rk, err) nxt = rk+1
if(nxt == sz)nxt = MPI_PROC_NULL
call MPI_SEND(buf, 1, MPI_REAL, nxt,& tag, MPI_COMM_WORLD, err)
При вызове MPI_SEND с джокером MPI_PROC_NULL
никакие данные отправлены не будут, а программа сразу перейдет к следующей процедуре с кодом MPI_SUCCESS.
Полезен при циклическом сдвиге процессов.
30