我已經定義了一個自定義結構,並希望使用MPI_Bsend(或MPI_Send)將它發送到另一個MPI進程 。C中的結構序列化和通過MPI傳輸
這裏是我的結構:
struct car{
int shifts;
int topSpeed;
}myCar;
然而,除了基本類型MPI似乎並不支持直接複雜的數據類型,如上述結構的「傳輸」。我聽說我可能不得不使用「序列化」。 我應該如何處理它並將'myCar'發送給進程5?
我已經定義了一個自定義結構,並希望使用MPI_Bsend(或MPI_Send)將它發送到另一個MPI進程 。C中的結構序列化和通過MPI傳輸
這裏是我的結構:
struct car{
int shifts;
int topSpeed;
}myCar;
然而,除了基本類型MPI似乎並不支持直接複雜的數據類型,如上述結構的「傳輸」。我聽說我可能不得不使用「序列化」。 我應該如何處理它並將'myCar'發送給進程5?
Jeremiah是對的 - MPI_Type_create_struct是去這裏的路。
重要的是要記住,MPI是一個圖書館,不是內置於語言;所以它不能「看到」什麼樣的結構看起來像序列化它本身。因此,要發送複雜的數據類型,您必須明確定義其佈局。在具有對序列化的本地支持的語言中,一組MPI包裝器可以協調地使用它;例如mpi4py利用python的pickle來透明地發送複雜的數據類型;但在C中,你必須捲起袖子並自己動手。
爲了您的結構,它看起來像這樣:
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
#include <stddef.h>
typedef struct car_s {
int shifts;
int topSpeed;
} car;
int main(int argc, char **argv) {
const int tag = 13;
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (size < 2) {
fprintf(stderr,"Requires at least two processes.\n");
exit(-1);
}
/* create a type for struct car */
const int nitems=2;
int blocklengths[2] = {1,1};
MPI_Datatype types[2] = {MPI_INT, MPI_INT};
MPI_Datatype mpi_car_type;
MPI_Aint offsets[2];
offsets[0] = offsetof(car, shifts);
offsets[1] = offsetof(car, topSpeed);
MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_car_type);
MPI_Type_commit(&mpi_car_type);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank == 0) {
car send;
send.shifts = 4;
send.topSpeed = 100;
const int dest = 1;
MPI_Send(&send, 1, mpi_car_type, dest, tag, MPI_COMM_WORLD);
printf("Rank %d: sent structure car\n", rank);
}
if (rank == 1) {
MPI_Status status;
const int src=0;
car recv;
MPI_Recv(&recv, 1, mpi_car_type, src, tag, MPI_COMM_WORLD, &status);
printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank,
recv.shifts, recv.topSpeed);
}
MPI_Type_free(&mpi_car_type);
MPI_Finalize();
return 0;
}
查看MPI_Type_create_struct
爲您的對象構建自定義MPI數據類型。使用它的一個例子是http://beige.ucs.indiana.edu/I590/node100.html。
我還是有點困惑..假設我定義了MPI結構並且現在想要使用它。您給出的鏈接狀態:MPI_Type_create_struct(5,array_of_block_lengths,array_of_displacements, array_of_types,&new_type);我現在應該做一些類似myCar =&new_type的事情嗎? – kstratis 2012-03-25 23:07:52
更重要的是...你能給我一個簡單但具體的例子來創建和傳輸特定的結構嗎? – kstratis 2012-03-25 23:28:43
問題解決。您提供的鏈接提供了所有的「理論」,但由於位移和低級細節,很容易讓業餘程序員混淆。但它似乎正好描述了底下的機制。 – kstratis 2012-03-26 00:41:27
雖然喬納森·德西的答案是正確的,這是過於複雜。 MPI提供更簡單和不太常見的類型構造函數,更適合您的問題。只有當你有不同的基類型(例如,一個int和一個浮點數)時才需要MPI_Type_create_struct
。
對於你的榜樣,一些更好的解決方案存在:
假設兩個整數在一個連續的內存區域對齊(即,像一個整數數組),你不需要導出類型在所有。只需發送/接收MPI_INT
類型的兩個元素與car
類型的變量的地址被用作發送/接收緩衝區:
MPI_Send(&send, 2, MPI_INT, dest, tag, MPI_COMM_WORLD);
MPI_Recv(&recv, 2, MPI_INT, src, tag, MPI_COMM_WORLD, &status);
如果要使用派生的數據類型(例如,對於可讀性或它的樂趣),你可以使用MPI_Type_contiguous
對應於數組:
MPI_Type_contiguous(2, MPI_INT, &mpi_car_type);
如果兩個整數對準不同的(最有可能並非如此,但它是依賴於機器和大量存在的MPI實現不同的平臺),你可以使用MPI_Type_indexed_block
:這需要位移的陣列(如MPI_Type_create_struct
),但只有一個OLDTYPE參數和每塊的塊長度由定義爲1:
MPI_Aint offsets[2];
offsets[0] = offsetof(car, shifts) ; //most likely going to be 0
offsets[1] = offsetof(car, topSpeed);
MPI_Type_indexed_block(2, offsets, MPI_INT);
儘管其他方案是語義上正確的,它閱讀起來很困難,可能會導致很大的性能損失。
感謝您提供非常全面和快速的回復。對此,我真的非常感激。你已經完全覆蓋了我。 (但是我認爲你忘了在頂部導致,否則編譯器會給出錯誤。) –
kstratis
2012-03-26 00:39:55
你是對的 - 需要offsetof()。我已經適當地更新了代碼。 – 2012-03-26 02:05:07