▶ MPI 中与数据打包传输有关的几个函数
● 函数 MPI_Pack() 与 MPI_Unpack() 的原型
1 MPI_METHOD MPI_Pack( 2 _In_opt_ const void* inbuf, // 指向待打包数据的指针 3 _In_range_(>= , 0) int incount, // 带打包数据元素个数 4 _In_ MPI_Datatype datatype, // 数据类型 5 _mpi_writes_bytes_(outsize) void* outbuf, // 指向打包输出缓冲区的指针 6 _In_range_(>= , 0) int outsize, // 缓冲区大小(单位为 Byte) 7 _mpi_position_(outsize) int* position, // 输出缓冲区中第一个用于打包的位置(地址偏移量) 8 _In_ MPI_Comm comm // 通信子 9 ); 10 11 MPI_METHOD MPI_Unpack( 12 _mpi_reads_bytes_(insize) const void* inbuf,// 指向待解包缓冲区的指针 13 _In_range_(>= , 0) int insize, // 缓冲区大小(单位为 Byte) 14 _mpi_position_(insize) int* position, // 输出缓冲区中第一个用于打包的位置(地址偏移量) 15 _When_(insize > 0, _Out_opt_) void* outbuf, // 指向解包后数据的指针 16 _In_range_(>= , 0) int outcount, // 解包元素个数 17 _In_ MPI_Datatype datatype, // 数据类型 18 _In_ MPI_Comm comm // 通信子 19 );
● 使用范例
1 int main(int argc, char *argv[]) 2 { 3 int rank, size, i, position; 4 char c[100], buffer[110];// 缓冲区大小 110,即 110 Byte 5 6 MPI_Init(&argc, &argv); 7 MPI_Comm_size(MPI_COMM_WORLD, &size); 8 MPI_Comm_rank(MPI_COMM_WORLD, &rank); 9 10 position = 0; // position 需要赋值为一个非负数,否则报错(?) 11 if (rank == 0) // 0 号进程打包 1 个整形变量和 1 个字符型数组到同一片内存中,发送给 1 号进程 12 { 13 for (i = 0; i < 100; c[i] = i, i++); 14 i = 120994; 15 MPI_Pack(&i, 1, MPI_INT, buffer, 110, &position, MPI_COMM_WORLD);// 打包和解包缓冲区时要注明大小(单位为 Byte) 16 MPI_Pack(c, 100, MPI_CHAR, buffer, 110, &position, MPI_COMM_WORLD); 17 MPI_Send(buffer, position, MPI_PACKED, 1, 0, MPI_COMM_WORLD); 18 } 19 if (rank == 1) 20 { 21 MPI_Recv(buffer, 110, MPI_PACKED, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 22 MPI_Unpack(buffer, 110, &position, &i, 1, MPI_INT, MPI_COMM_WORLD); 23 MPI_Unpack(buffer, 110, &position, c, 100, MPI_CHAR, MPI_COMM_WORLD); 24 printf("i=%d, c[0] = %d, c[99] = %d\n", i, (int)c[0], (int)c[99]); 25 fflush(stdout); 26 } 27 28 MPI_Finalize(); 29 return 0; 30 }
● 输出结果
D:\Code\MPI\MPIProjectTemp\x64\Debug>mpiexec -n 2 -l MPIProjectTemp.exe [1]i=120994, c[0] = 0, c[99] = 99
▶ 函数 MPI_Size(),计算打包所需的缓冲区大小。上面的打包和解包过程中使用的是静态内存空间,对于较为复杂的数据类型,可以用 MPI 内建函数来计算需要的空间大小,防止缓冲区不足或者空间浪费。
● 函数原型
1 MPI_METHOD MPI_Pack_size( 2 _In_range_(>= , 0) int incount, // 数据数量 3 _In_ MPI_Datatype datatype, // 数据类型 4 _In_ MPI_Comm comm, // 通信子 5 _mpi_out_(size, MPI_UNDEFINED) int *size// 输出所需尺寸(单位为 Byte) 6 );
● 使用范例
1 { 2 int size,a[10000]; 3 char *buffer; 4 MPI_Datatype col; 5 MPI_Type_vector(10, 1, 100, MPI_INT, &col); 6 MPI_Type_commit(&col); // 声明并提交一个数据类型 7 MPI_Pack_size(1, col, MPI_COMM_WORLD, &size); // 计算打包一个这样的类型需要的空间大小 8 buffer = (char *)malloc((unsigned)size); // 动态声明一个缓冲区用于打包 9 MPI_Pack(a, 1, col, buffer, size, &position, MPI_COMM_WORLD); 10 }
▶ 函数 MPI_Pack_external(),MPI_Unpack_external(),MPI_Pack_external_size(),与上面的打包、解包、求大小函数类似,将需要打包的数据转换成连续的内存空间进行传递
● 函数原型,相比上面的打包、解包、求空间大小的函数,多了数据描述参数,少了通信子参数
1 MPI_METHOD MPI_Pack_external( 2 _In_z_ const char* datarep, // 数据描述,与保存格式有关,不能随意写 3 _In_opt_ const void* inbuf, 4 _In_range_(>= , 0) int incount, 5 _In_ MPI_Datatype datatype, 6 _mpi_writes_bytes_(outsize) void* outbuf, 7 _In_range_(>= , 0) MPI_Aint outsize, 8 _mpi_position_(outsize) MPI_Aint* position 9 ); 10 11 MPI_METHOD MPI_Unpack_external( 12 _In_z_ const char* datarep, 13 _In_reads_bytes_opt_(insize) const void* inbuf, 14 _In_range_(>= , 0) MPI_Aint insize, 15 _mpi_position_(insize) MPI_Aint* position, 16 _When_(insize > 0, _Out_opt_) void* outbuf, 17 _In_range_(>= , 0) int outcount, 18 _In_ MPI_Datatype datatype 19 ); 20 21 MPI_METHOD MPI_Pack_external_size( 22 _In_z_ const char* datarep, 23 _In_range_(>= , 0) int incount, 24 _In_ MPI_Datatype datatype, 25 _Out_ MPI_Aint* size 26 );
● 使用范例
1 { 2 int comSize, comRank; 3 MPI_Aint dataSize, position; 4 double data[5]; 5 char *buf; 6 7 MPI_Init(&argc, &argv); 8 MPI_Comm_rank(MPI_COMM_WORLD, &comRank); 9 10 MPI_Pack_external_size("external32", 5, MPI_DOUBLE, &dataSize); 11 buf = (char *)malloc(dataSize); 12 13 position = 0; 14 if (comRank == 0) 15 { 16 MPI_Pack_external("external32", &data, 5, MPI_DOUBLE, buf, dataSize, &position); 17 MPI_Send(buf, position, MPI_PACKED, 1, 0, MPI_COMM_WORLD); 18 } 19 else 20 { 21 MPI_Recv(buf, dataSize, MPI_PACKED, 0, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE); 22 MPI_Unpack_external("external32", buf, dataSize, &position, &data, 5, MPI_DOUBLE); 23 } 24 MPI_Finalize(); 25 return 0; 26 }