Под сообщением в понимается массив однотипных данных, расположенных в последовательных ячейках памяти. Часто в программах требуются пересылки более сложных объектов данных, состоящих из разнотипных элементов или расположенных не в последовательных ячейках памяти. В этом случае можно либо посылать данные небольшими порциями расположенных подряд элементов одного типа, либо использовать копирование данных перед отсылкой в некоторый промежуточный буфер. Оба варианта являются достаточно неудобными и требуют дополнительных затрат как времени, так и оперативной памяти.
Для пересылки разнотипных данных в предусмотрены два специальных способа:
Создание типа данных состоит из двух этапов:
После регистрации
MPI_TYPE_CONTIGUOUS(COUNT, TYPE, NEWTYPE, IERR) INTEGER COUNT, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT последовательно расположенных элементов TYPE. Фактически создаваемый тип данных представляет массив данных базового типа как отдельный объект.
В следующем примере создается новый тип данных newtype, который в дальнейшем (после регистрации типа) может использоваться для пересылки пяти расположенных подряд целых чисел.
call MPI_TYPE_CONTIGUOUS(5, MPI_INTEGER, newtype, ierr) MPI_TYPE_VECTOR(COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLEN элементов TYPE. Следующий блок начинается через STRIDE элементов
В следующем примере создается новый тип данных newtype, который после регистрации может быть использован для пересылки как единого целого шести элементов данных, которые можно представить следующим образом (тип элемента данных, количество элементов данных от начала буфера посылки):
{(MPI_REAL, 0), (MPI_REAL, 1), (MPI_REAL, 2), (MPI_REAL, 5), (MPI_REAL, 6), (MPI_REAL, 7)}
count = 2 blocklen = 3 stride = 5
call MPI_TYPE_VECTOR(count, blocklen, stride,
MPI_REAL, newtype, ierr)
MPI_TYPE_HVECTOR(COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR) INTEGER COUNT,
BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLEN элементов TYPE. Следующий блок начинается через STRIDE байт после начала предыдущего блока.
MPI_TYPE_INDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов DISPLS (i) элементов
В следующем примере задается тип данных newtype для описания нижнетреугольной матрицы типа (при этом учитывается, что в языке Фортран массивы хранятся по столбцам).
do i = 1, n blocklens (i) = n-i + 1 displs(i) = n*(i-1)+i-1 end do call MPI_TYPE_INDEXED(n, blocklens, displs, MPI_DOUBLE_PRECISION, newtype, ierr) MPI_TYPE_HINDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов DISPLS (I) байт с начала буфера посылки.
MPI_TYPE_STRUCT(COUNT, BLOCKLENS, DISPLS, TYPES, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPES(*), NEWTYPE, IERR
Создание NEWTYPE из COUNT блоков по BLOCKLENS (i) элементов типа TYPES (I) . I-й блок начинается через DISPLS (I) байт с начала буфера посылки.
В следующем примере создается новый тип данных newtype, который после регистрации может быть использован для пересылки как единого целого пяти элементов данных, которые можно представить следующим образом (тип элемента данных, количество байт от начала буфера посылки):
{(MPI_DOUBLE_PRECISION, 0), (MPI_DOUBLE_PRECISION, 8), (MPI_DOUBLE_PRECISION, 16),
(MPI_CHARACTER, 24), (MPI_CHARACTER, 25)}
blocklens(1) = 3 blocklens(2) = 2
types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER displs(1) = 0 displs(2) = 24
call MPI_TYPE_STRUCT(2, blocklens, displs, types,
newtype, ierr)
MPI_TYPE_COMMIT(DATATYPE, IERR) INTEGER DATATYPE, IERR
Регистрация созданного производного типа данных . После регистрации этот тип данных можно использовать в операциях обмена наравне с предопределенными типами данных. Предопределенные типы данных регистрировать не нужно.
MPI_TYPE_FREE(DATATYPE, IERR) INTEGER DATATYPE, IERR
. Параметр устанавливается в значение MPI_DATATYPE_NULL. Гарантируется, что любой начатый обмен, использующий данные аннулируемого типа, будет нормально завершен. При этом производные от типы данных остаются и могут использоваться дальше. Предопределенные типы данных не могут быть аннулированы.
MPI_TYPE_SIZE(DATATYPE, SIZE, IERR) INTEGER DATATYPE, SIZE, IERR
Определение размера SIZE типа данных в байтах (объема памяти, занимаемого одним элементом данного типа).
MPI_ADDRESS(LOCATION, ADDRESS, IERR) <type> LOCATION(*) INTEGER ADDRESS, IERR
Определение абсолютного байт-адреса ADDRESS размещения массива LOCATION в оперативной памяти компьютера. Адрес отсчитывается от базового адреса, значение которого содержится в системной константе MPI_BOTTOM. Процедура позволяет определять абсолютные адреса объектов как в языке Фортран, так и в Си, хотя в Си для этого предусмотрены иные средства. В языке Си параметр ADDRESS имеет тип MPi_Aint.
В следующем примере описывается новый тип данных newtype, который после регистрации используется для пересылки как единого целого двух элементов данных типов и character (1). В качестве адреса буфера посылки используется базовый адрес MPI_BOTTOM, а для определения datl и dat2 используются вызовы процедуры MPI_ADDRESS. Перед пересылкой новый тип регистрируется при помощи вызова процедуры MPI_TYPE_COMMIT. Заметим, что пересылается один элемент данных производного типа, хотя он и состоит из двух разнотипных элементов.
blocklens(1) = 1 blocklens(2) = 1 types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER call MPI_ADDRESS(dat1, address(1), ierr) displs(1) = address(1) call MPI_ADDRESS(dat2, address(2), ierr) displs(2) = address(2) call MPI_TYPE_STRUCT(2, blocklens, displs, types, newtype, ierr) call MPI_TYPE_COMMIT(newtype, ierr) call MPI_SEND(MPI_BOTTOM, 1, newtype, dest, tag, MPI_COMM_WORLD, ierr) MPI_TYPE_LB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах нижней границы элемента типа данных от начала
MPI_TYPE_UB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах верхней границы элемента типа данных от начала
MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERR) INTEGER DATATYPE, EXTENT, IERR
Определение диапазона (разницы между верхней и нижней границами элемента данного типа) типа данных В байтах.
В следующем примере matr_rev, создаваемый процедурой MPI_TYPE_VECTOR, описывает локальную часть матрицы данного процесса в переставленными в обратном порядке столбцами. После регистрации этот тип данных может использоваться при пересылке. Программа работает правильно, если размер матрицы N делится нацело на число процессов приложения.
program example19 include 'mpif.h' integer ierr, rank, size, N, nl parameter (N = 8) double precision a(N, N), b(N, N) call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) nl = (N-1)/size+1 call work (a, b, N, nl, size, rank) call MPI_FINALIZE(ierr) end subroutine work(a, b, n, nl, size, rank) include 'mpif.h' integer ierr, rank, size, n, nl, ii, matr_rev double precision a(n, nl), b(n, nl) integer i, j, status(MPI_STATUS_SIZE) do j = 1, nl do i = 1, n b(i,j) = 0.d0 ii = j+rank*nl a(i,j) = 100*ii+i enddo enddo call MPI_TYPE_VECTOR(nl, n, -n, MPI_DOUBLE_PRECISION, matr_rev, ierr) call MPI_TYPE_COMMIT(matr_rev, ierr) call MPI_SENDRECV(a(1, nl), 1, MATR_REV, size-rank-1, 1, b, nl*n, MPI_DOUBLE_PRECISION, size-rank-1, 1, MPI_COMM_WORLD, status, ierr) do j = 1, nl do i = 1, n print *, 'process ', rank, ': ', j+rank*nl, ' ', i, a(i,j), ' ', b(i,j) enddo enddo end
Для пересылок разнородных данных наряду с созданием
MPI_PACK(INBUF, INCOUNT, DATATYPE, OUTBUF, OUTSIZE, POSITION, COMM, IERR) <type> INBUF(*), OUTBUF(*) INTEGER INCOUNT, DATATYPE, OUTSIZE, POSITION, COMM, IERR
Упаковка INCOUNT элементов типа из массива INBUF в массив OUTBUF со сдвигом POSITION байт от начала массива. Буфер OUTBUF должен содержать по крайней мере OUTSIZE байт. После выполнения процедуры параметр POSITION увеличивается на число байт, равное размеру записи. Параметр сомм указывает на коммуникатор, в котором в дальнейшем будет пересылаться сообщение. Для пересылки упакованных данных используется тип данных MPI_PACKED.
MPI_UNPACK(INBUF, INSIZE, POSITION, OUTBUF, OUTCOUNT, DATATYPE, COMM, IERR) <type> INBUF(*), OUTBUF(*) INTEGER INSIZE, POSITION, OUTCOUNT, DATATYPE, COMM, IERR
Распаковка OUTCOUNT элементов типа из массива INBUF со сдвигом POSITION байт от начала массива в массив OUTBUF. Массив INBUF имеет размер не менее INSIZE байт.
MPI_PACK_SIZE(INCOUNT, DATATYPE, COMM, SIZE, IERR) INTEGER INCOUNT, DATATYPE, COMM, SIZE, IERR
Определение необходимого объема памяти SIZE (в байтах) для упаковки INCOUNT элементов типа . Необходимый для упаковки размер может превышать сумму размеров пакуемых элементов данных.
В следующем примере массив buf используется в качестве буфера для упаковки 10 элементов массива а типа real и 10 элементов массива b типа character. Полученное сообщение пересылается процедурой MPI_BCAST ОТ процесса о всем остальным процессам, полученное сообщение распаковывается при помощи вызовов процедур MPI_UNPACK.
program example2 0 include 'mpif.h' integer ierr, rank, position real a(10) character b(10), buf(100) call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) do i = 1, 10 a(i) = rank + 1.0 if(rank .eq. 0) then b(i) = 'a' else b(i) = 'b' end if end do position=0 if(rank .eq. 0) then call MPI_PACK(a, 10, MPI_REAL, buf, 100, position, MPI_COMM_WORLD, ierr) call MPI_PACK(b, 10, MPI_CHARACTER, buf, 100, position, MPI_COMM_WORLD, ierr) call MPI_BCAST(buf, 100, MPI_PACKED, 0, MPI_COMM_WORLD, ierr) else call MPI_BCAST(buf, 100, MPI_PACKED, 0, MPI_COMM_WORLD, ierr) position=0 call MPI UNPACK(buf, 100, position, a, 10, MPI_REAL, MPI_COMM_WORLD, ierr) call MPI UNPACK(buf, 100, position, b, 10, MPI_CHARACTER, MPI_COMM_WORLD, ierr) end if print *, 'procecc ', rank, ' a=', a, ' b=', b call MPI_FINALIZE(ierr) end
Как соотносятся значения, возвращаемые процедурами MPI_TYPE_SIZE и MPI_TYPE_EXTENT?
MPI_TYPE_COMMIT?MPI_GET_PROCESSOR_NAME ).Под сообщением в понимается массив однотипных данных, расположенных в последовательных ячейках памяти. Часто в программах требуются пересылки более сложных объектов данных, состоящих из разнотипных элементов или расположенных не в последовательных ячейках памяти. В этом случае можно либо посылать данные небольшими порциями расположенных подряд элементов одного типа, либо использовать копирование данных перед отсылкой в некоторый промежуточный буфер. Оба варианта являются достаточно неудобными и требуют дополнительных затрат как времени, так и оперативной памяти.
Для пересылки разнотипных данных в предусмотрены два специальных способа:
Создание типа данных состоит из двух этапов:
После регистрации
MPI_TYPE_CONTIGUOUS(COUNT, TYPE, NEWTYPE, IERR) INTEGER COUNT, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT последовательно расположенных элементов TYPE. Фактически создаваемый тип данных представляет массив данных базового типа как отдельный объект.
В следующем примере создается новый тип данных newtype, который в дальнейшем (после регистрации типа) может использоваться для пересылки пяти расположенных подряд целых чисел.
call MPI_TYPE_CONTIGUOUS(5, MPI_INTEGER, newtype, ierr) MPI_TYPE_VECTOR(COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLEN элементов TYPE. Следующий блок начинается через STRIDE элементов
В следующем примере создается новый тип данных newtype, который после регистрации может быть использован для пересылки как единого целого шести элементов данных, которые можно представить следующим образом (тип элемента данных, количество элементов данных от начала буфера посылки):
{(MPI_REAL, 0), (MPI_REAL, 1), (MPI_REAL, 2), (MPI_REAL, 5), (MPI_REAL, 6), (MPI_REAL, 7)}
count = 2 blocklen = 3 stride = 5
call MPI_TYPE_VECTOR(count, blocklen, stride,
MPI_REAL, newtype, ierr)
MPI_TYPE_HVECTOR(COUNT, BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR) INTEGER COUNT,
BLOCKLEN, STRIDE, TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLEN элементов TYPE. Следующий блок начинается через STRIDE байт после начала предыдущего блока.
MPI_TYPE_INDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов DISPLS (i) элементов
В следующем примере задается тип данных newtype для описания нижнетреугольной матрицы типа (при этом учитывается, что в языке Фортран массивы хранятся по столбцам).
do i = 1, n blocklens (i) = n-i + 1 displs(i) = n*(i-1)+i-1 end do call MPI_TYPE_INDEXED(n, blocklens, displs, MPI_DOUBLE_PRECISION, newtype, ierr) MPI_TYPE_HINDEXED(COUNT, BLOCKLENS, DISPLS, TYPE, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPE, NEWTYPE, IERR
Создание нового типа данных NEWTYPE, состоящего из COUNT блоков по BLOCKLENS (I) элементов DISPLS (I) байт с начала буфера посылки.
MPI_TYPE_STRUCT(COUNT, BLOCKLENS, DISPLS, TYPES, NEWTYPE, IERR) INTEGER COUNT, BLOCKLENS(*), DISPLS(*), TYPES(*), NEWTYPE, IERR
Создание NEWTYPE из COUNT блоков по BLOCKLENS (i) элементов типа TYPES (I) . I-й блок начинается через DISPLS (I) байт с начала буфера посылки.
В следующем примере создается новый тип данных newtype, который после регистрации может быть использован для пересылки как единого целого пяти элементов данных, которые можно представить следующим образом (тип элемента данных, количество байт от начала буфера посылки):
{(MPI_DOUBLE_PRECISION, 0), (MPI_DOUBLE_PRECISION, 8), (MPI_DOUBLE_PRECISION, 16),
(MPI_CHARACTER, 24), (MPI_CHARACTER, 25)}
blocklens(1) = 3 blocklens(2) = 2
types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER displs(1) = 0 displs(2) = 24
call MPI_TYPE_STRUCT(2, blocklens, displs, types,
newtype, ierr)
MPI_TYPE_COMMIT(DATATYPE, IERR) INTEGER DATATYPE, IERR
Регистрация созданного производного типа данных . После регистрации этот тип данных можно использовать в операциях обмена наравне с предопределенными типами данных. Предопределенные типы данных регистрировать не нужно.
MPI_TYPE_FREE(DATATYPE, IERR) INTEGER DATATYPE, IERR
. Параметр устанавливается в значение MPI_DATATYPE_NULL. Гарантируется, что любой начатый обмен, использующий данные аннулируемого типа, будет нормально завершен. При этом производные от типы данных остаются и могут использоваться дальше. Предопределенные типы данных не могут быть аннулированы.
MPI_TYPE_SIZE(DATATYPE, SIZE, IERR) INTEGER DATATYPE, SIZE, IERR
Определение размера SIZE типа данных в байтах (объема памяти, занимаемого одним элементом данного типа).
MPI_ADDRESS(LOCATION, ADDRESS, IERR) <type> LOCATION(*) INTEGER ADDRESS, IERR
Определение абсолютного байт-адреса ADDRESS размещения массива LOCATION в оперативной памяти компьютера. Адрес отсчитывается от базового адреса, значение которого содержится в системной константе MPI_BOTTOM. Процедура позволяет определять абсолютные адреса объектов как в языке Фортран, так и в Си, хотя в Си для этого предусмотрены иные средства. В языке Си параметр ADDRESS имеет тип MPi_Aint.
В следующем примере описывается новый тип данных newtype, который после регистрации используется для пересылки как единого целого двух элементов данных типов и character (1). В качестве адреса буфера посылки используется базовый адрес MPI_BOTTOM, а для определения datl и dat2 используются вызовы процедуры MPI_ADDRESS. Перед пересылкой новый тип регистрируется при помощи вызова процедуры MPI_TYPE_COMMIT. Заметим, что пересылается один элемент данных производного типа, хотя он и состоит из двух разнотипных элементов.
blocklens(1) = 1 blocklens(2) = 1 types(1) = MPI_DOUBLE_PRECISION types(2) = MPI_CHARACTER call MPI_ADDRESS(dat1, address(1), ierr) displs(1) = address(1) call MPI_ADDRESS(dat2, address(2), ierr) displs(2) = address(2) call MPI_TYPE_STRUCT(2, blocklens, displs, types, newtype, ierr) call MPI_TYPE_COMMIT(newtype, ierr) call MPI_SEND(MPI_BOTTOM, 1, newtype, dest, tag, MPI_COMM_WORLD, ierr) MPI_TYPE_LB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах нижней границы элемента типа данных от начала
MPI_TYPE_UB(DATATYPE, DISPL, IERR) INTEGER DATATYPE, DISPL, IERR
Определение смещения DISPL В байтах верхней границы элемента типа данных от начала
MPI_TYPE_EXTENT(DATATYPE, EXTENT, IERR) INTEGER DATATYPE, EXTENT, IERR
Определение диапазона (разницы между верхней и нижней границами элемента данного типа) типа данных В байтах.
В следующем примере matr_rev, создаваемый процедурой MPI_TYPE_VECTOR, описывает локальную часть матрицы данного процесса в переставленными в обратном порядке столбцами. После регистрации этот тип данных может использоваться при пересылке. Программа работает правильно, если размер матрицы N делится нацело на число процессов приложения.
program example19 include 'mpif.h' integer ierr, rank, size, N, nl parameter (N = 8) double precision a(N, N), b(N, N) call MPI_INIT(ierr) call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) nl = (N-1)/size+1 call work (a, b, N, nl, size, rank) call MPI_FINALIZE(ierr) end subroutine work(a, b, n, nl, size, rank) include 'mpif.h' integer ierr, rank, size, n, nl, ii, matr_rev double precision a(n, nl), b(n, nl) integer i, j, status(MPI_STATUS_SIZE) do j = 1, nl do i = 1, n b(i,j) = 0.d0 ii = j+rank*nl a(i,j) = 100*ii+i enddo enddo call MPI_TYPE_VECTOR(nl, n, -n, MPI_DOUBLE_PRECISION, matr_rev, ierr) call MPI_TYPE_COMMIT(matr_rev, ierr) call MPI_SENDRECV(a(1, nl), 1, MATR_REV, size-rank-1, 1, b, nl*n, MPI_DOUBLE_PRECISION, size-rank-1, 1, MPI_COMM_WORLD, status, ierr) do j = 1, nl do i = 1, n print *, 'process ', rank, ': ', j+rank*nl, ' ', i, a(i,j), ' ', b(i,j) enddo enddo end
Для пересылок разнородных данных наряду с созданием
MPI_PACK(INBUF, INCOUNT, DATATYPE, OUTBUF, OUTSIZE, POSITION, COMM, IERR) <type> INBUF(*), OUTBUF(*) INTEGER INCOUNT, DATATYPE, OUTSIZE, POSITION, COMM, IERR
Упаковка INCOUNT элементов типа из массива INBUF в массив OUTBUF со сдвигом POSITION байт от начала массива. Буфер OUTBUF должен содержать по крайней мере OUTSIZE байт. После выполнения процедуры параметр POSITION увеличивается на число байт, равное размеру записи. Параметр сомм указывает на коммуникатор, в котором в дальнейшем будет пересылаться сообщение. Для пересылки упакованных данных используется тип данных MPI_PACKED.
MPI_UNPACK(INBUF, INSIZE, POSITION, OUTBUF, OUTCOUNT, DATATYPE, COMM, IERR) <type> INBUF(*), OUTBUF(*) INTEGER INSIZE, POSITION, OUTCOUNT, DATATYPE, COMM, IERR
Распаковка OUTCOUNT элементов типа из массива INBUF со сдвигом POSITION байт от начала массива в массив OUTBUF. Массив INBUF имеет размер не менее INSIZE байт.
MPI_PACK_SIZE(INCOUNT, DATATYPE, COMM, SIZE, IERR) INTEGER INCOUNT, DATATYPE, COMM, SIZE, IERR
Определение необходимого объема памяти SIZE (в байтах) для упаковки INCOUNT элементов типа . Необходимый для упаковки размер может превышать сумму размеров пакуемых элементов данных.
В следующем примере массив buf используется в качестве буфера для упаковки 10 элементов массива а типа real и 10 элементов массива b типа character. Полученное сообщение пересылается процедурой MPI_BCAST ОТ процесса о всем остальным процессам, полученное сообщение распаковывается при помощи вызовов процедур MPI_UNPACK.
program example2 0 include 'mpif.h' integer ierr, rank, position real a(10) character b(10), buf(100) call MPI_INIT(ierr) call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr) do i = 1, 10 a(i) = rank + 1.0 if(rank .eq. 0) then b(i) = 'a' else b(i) = 'b' end if end do position=0 if(rank .eq. 0) then call MPI_PACK(a, 10, MPI_REAL, buf, 100, position, MPI_COMM_WORLD, ierr) call MPI_PACK(b, 10, MPI_CHARACTER, buf, 100, position, MPI_COMM_WORLD, ierr) call MPI_BCAST(buf, 100, MPI_PACKED, 0, MPI_COMM_WORLD, ierr) else call MPI_BCAST(buf, 100, MPI_PACKED, 0, MPI_COMM_WORLD, ierr) position=0 call MPI UNPACK(buf, 100, position, a, 10, MPI_REAL, MPI_COMM_WORLD, ierr) call MPI UNPACK(buf, 100, position, b, 10, MPI_CHARACTER, MPI_COMM_WORLD, ierr) end if print *, 'procecc ', rank, ' a=', a, ' b=', b call MPI_FINALIZE(ierr) end
Как соотносятся значения, возвращаемые процедурами MPI_TYPE_SIZE и MPI_TYPE_EXTENT?
MPI_TYPE_COMMIT?MPI_GET_PROCESSOR_NAME ).Для получения официальных документов о завершении программы дополнительного профессионального образования (удостоверения о повышении квалификации, дипломов о профессиональной переподготовке и MBA) необходимо предоставить:
Внимание! Вы можете не заказывать доставку бумажной версии официального документы, а скачать его в электронном виде и распечатать самостоятельно. Информация о выданном документе в течение 1 месяца загружается в Федеральную информационную систему «Федеральный реестр сведений о документах об образовании и (или) о квалификации, документах об обучении» - ФИС ФРДО.
Доступ на новый сайт осуществляется с использованием адреса электронной почты, который был указан вами при регистрации на "старом". Мы постарались перенести все ваши данные с прежнего ресурса, однако не исключена вероятность потери части информации.
При возникновении проблемы со входом, воспользуйтесь функцией сброса пароля
Если вы обнаружите несоответствия, пожалуйста, сообщите нам.