Если данные, которые будут посланы, хранятся в последовательных элементах массива, то лучше всего использовать аргументы count и datatype коммуникационных функций. Этот подход не включает никаких дополнительных действий, например, вызовов для создания производных типов данных или MPI_Pack/MPI_Unpack.
Если большое количество элементов не находится в смежных ячейках памяти, то построение производного типа данных будет дешевле и производительнее, чем большое количество вызовов MPI_Pack / MPI_Unpack.
Если все данные имеют одинаковый тип и хранятся в памяти равномерно (например, колонки матрицы), то наверняка будет проще и быстрее использовать производный тип данных, чем MPI_Pack / MPI_Unpack. Далее, если все данные имеют одинаковый тип, но хранятся в ячейках памяти, распределенных нерегулярно, то легче и эффективнее создать производный тип, используя MPI_Type_indexed. Наконец, если данные являются гетерогенными и процессы неоднократно посылают тот же самый набор данных (например, номер ряда, номер колонки, элемент матрицы), то лучше использовать производный тип. При этом затраты на создание производного типа возникнут только однажды, в то время как затраты на вызов MPI_Pack / MPI_Unpack будут возникать каждый раз, когда передаются данные.
Однако в некоторых ситуациях использование MPI_Pack /
MPI_Unpack
является предпочтительным. Так, можно избежать коллективного
использования системной буферизации при упаковке, поскольку данные явно
сохраняются в определенном пользователем буфере. Система может использовать
это, отметив, что типом сообщения является MPI_PACKED. Пользователь
также может посылать сообщения "переменной длины",
упаковывая число элементов в начале буфера. Пусть, например, необходимо
посылать строки разреженной матрицы. Если строка хранится в виде пары
массивов, где первый содержит индексы колонок, а второй содержит соответствующие
элементы матрицы, то можно посылать строку от процесса 0 к процессу
1 следующим образом:
int* column_subscripts;
/* количество ненулевых элементов в строке */
int nonzeroes;
int position;
int row_number;
char* buffer[HUGE]; /* HUGE является константой */
MPI_Status status;
. . .
if (my_rank == 0) {
/* Получить количество ненулевых элементов строки. */
/* Выделить память для строки. */
/* Инициализировать массивы элементов и индексов */
. . .
/* Упаковать и послать данные */
position = 0;
MPI_Pack(&nonzeroes, 1, MPI_INT, buffer, HUGE,
&position, MPI_COMM_WORLD);
MPI_Pack(&row_number, 1, MPI_INT, buffer, HUGE,
&position, MPI_COMM_WORLD);
MPI_Pack(entries, nonzeroes, MPI_FLOAT, buffer,
HUGE, &position, MPI_COMM_WORLD);
MPI_Pack(column_subscripts, nonzeroes, MPI_INT,
buffer, HUGE, &position, MPI_COMM_WORLD);
MPI_Send(buffer, position, MPI_PACKED, 1, 193,
MPI_COMM_WORLD);
} else { /* my_rank == 1 */
MPI_Recv(buffer, HUGE, MPI_PACKED, 0, 193,
MPI_COMM_WORLD, &status);
position = 0;
MPI_Unpack(buffer, HUGE, &position, &nonzeroes, 1,
MPI_INT, MPI_COMM_WORLD);
MPI_Unpack(buffer, HUGE, &position, &row_number, 1,
MPI_INT, MPI_COMM_WORLD);
/* Выделить память для массивов */
entries = (float *) malloc(nonzeroes*sizeof(float));
column_subscripts =
(int *) malloc(nonzeroes*sizeof(int));
MPI_Unpack(buffer, HUGE, &position, entries,
nonzeroes, MPI_FLOAT, MPI_COMM_WORLD);
MPI_Unpack(buffer, HUGE, &position,
column_subscripts, nonzeroes, MPI_INT,
MPI_COMM_WORLD);
}