next up previous contents
Next: Коммуникаторы и топологии Up: Группировка данных для пересылки Previous: Упаковка и распаковка   Contents

Выбор используемого метода передачи данных

Если данные, которые будут посланы, хранятся в последовательных элементах массива, то лучше всего использовать аргументы 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 следующим образом:

float* entries;

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);

}



2004-06-22