▶ 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 }