在C中进行结构化序列化并通过MPI进行传输

我已经定义了一个自定义结构,并希望使用MPI_Bsend(或MPI_Send)将其发送到另一个MPI进程。


这是我的结构:


struct car{

  int shifts;

  int topSpeed;

}myCar;

但是,除了基本类型,MPI似乎不支持复杂数据类型的直接“传输”,如上面的struct。我听说我可能必须使用“序列化”。我应该如何处理并将“ myCar”发送给进程5?


莫回无
浏览 572回答 3
3回答

潇湘沐

耶利米是对的-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 {&nbsp; &nbsp; &nbsp; &nbsp; int shifts;&nbsp; &nbsp; &nbsp; &nbsp; int topSpeed;} car;int main(int argc, char **argv) {&nbsp; &nbsp; const int tag = 13;&nbsp; &nbsp; int size, rank;&nbsp; &nbsp; MPI_Init(&argc, &argv);&nbsp; &nbsp; MPI_Comm_size(MPI_COMM_WORLD, &size);&nbsp; &nbsp; if (size < 2) {&nbsp; &nbsp; &nbsp; &nbsp; fprintf(stderr,"Requires at least two processes.\n");&nbsp; &nbsp; &nbsp; &nbsp; exit(-1);&nbsp; &nbsp; }&nbsp; &nbsp; /* create a type for struct car */&nbsp; &nbsp; const int nitems=2;&nbsp; &nbsp; int&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; blocklengths[2] = {1,1};&nbsp; &nbsp; MPI_Datatype types[2] = {MPI_INT, MPI_INT};&nbsp; &nbsp; MPI_Datatype mpi_car_type;&nbsp; &nbsp; MPI_Aint&nbsp; &nbsp; &nbsp;offsets[2];&nbsp; &nbsp; offsets[0] = offsetof(car, shifts);&nbsp; &nbsp; offsets[1] = offsetof(car, topSpeed);&nbsp; &nbsp; MPI_Type_create_struct(nitems, blocklengths, offsets, types, &mpi_car_type);&nbsp; &nbsp; MPI_Type_commit(&mpi_car_type);&nbsp; &nbsp; MPI_Comm_rank(MPI_COMM_WORLD, &rank);&nbsp; &nbsp; if (rank == 0) {&nbsp; &nbsp; &nbsp; &nbsp; car send;&nbsp; &nbsp; &nbsp; &nbsp; send.shifts = 4;&nbsp; &nbsp; &nbsp; &nbsp; send.topSpeed = 100;&nbsp; &nbsp; &nbsp; &nbsp; const int dest = 1;&nbsp; &nbsp; &nbsp; &nbsp; MPI_Send(&send,&nbsp; &nbsp;1, mpi_car_type, dest, tag, MPI_COMM_WORLD);&nbsp; &nbsp; &nbsp; &nbsp; printf("Rank %d: sent structure car\n", rank);&nbsp; &nbsp; }&nbsp; &nbsp; if (rank == 1) {&nbsp; &nbsp; &nbsp; &nbsp; MPI_Status status;&nbsp; &nbsp; &nbsp; &nbsp; const int src=0;&nbsp; &nbsp; &nbsp; &nbsp; car recv;&nbsp; &nbsp; &nbsp; &nbsp; MPI_Recv(&recv,&nbsp; &nbsp;1, mpi_car_type, src, tag, MPI_COMM_WORLD, &status);&nbsp; &nbsp; &nbsp; &nbsp; printf("Rank %d: Received: shifts = %d topSpeed = %d\n", rank,&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;recv.shifts, recv.topSpeed);&nbsp; &nbsp; }&nbsp; &nbsp; MPI_Type_free(&mpi_car_type);&nbsp; &nbsp; MPI_Finalize();&nbsp; &nbsp; return 0;}

慕少森

尽管乔纳森·杜尔西(Jonathan Dursi)的回答是正确的,但它过于复杂。MPI提供了更简单,通用性更小的类型构造函数,更适合您的问题。MPI_Type_create_struct仅当您具有不同的基本类型(例如int和float)时才需要。对于您的示例,存在几种更好的解决方案:假设两个整数在连续的内存区域中对齐(即,就像整数数组一样),则根本不需要派生的数据类型。只需发送/接收两个具有type MPI_INT变量的地址的type元素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),但是只有一个旧类型参数,每个块的块长按定义为1:MPI_Aint offsets[2];offsets[0] = offsetof(car, shifts) ; //most likely going to be 0&nbsp;offsets[1] = offsetof(car, topSpeed);MPI_Type_indexed_block(2, offsets, MPI_INT);尽管其他解决方案在语义上是正确的,但它很难阅读,并且可能会导致较大的性能损失。

四季花海

int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm)OpenMPI将发送count * sizeof(datatype)从开始的连续字节,buf以允许发送类似int数组的内容。例如,如果声明一个10 int数组int arr[10],则可以使用MPI_Send(arr, 10, MPI_INT, 1, 0, MPI_COMM_WORLD);并收到类似的消息。由于buf是空指针,我们可以通过发送sizeof(my_struct)字节并在接收端将其强制转换为结构来滥用此结构来发送结构。这是一个例子:#include "mpi.h"#include <stdio.h>typedef struct&nbsp;{&nbsp; &nbsp; char a;&nbsp; &nbsp; int b;&nbsp; &nbsp; short c;} my_struct;int main (int argc, char *argv[]){&nbsp; &nbsp; int&nbsp; numtasks, taskid;&nbsp; &nbsp; MPI_Init(&argc, &argv);&nbsp; &nbsp; MPI_Comm_rank(MPI_COMM_WORLD, &taskid);&nbsp; &nbsp; MPI_Comm_size(MPI_COMM_WORLD, &numtasks);&nbsp; &nbsp; if (taskid == 0)&nbsp;&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; my_struct m;&nbsp; &nbsp; &nbsp; &nbsp; m.a = '!';&nbsp; &nbsp; &nbsp; &nbsp; m.b = 1234;&nbsp; &nbsp; &nbsp; &nbsp; m.c = 5678;&nbsp; &nbsp; &nbsp; &nbsp; MPI_Send(&m, sizeof(my_struct), MPI_CHAR, 1, 0, MPI_COMM_WORLD);&nbsp; &nbsp; }&nbsp; &nbsp; else&nbsp;&nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; my_struct m;&nbsp; &nbsp; &nbsp; &nbsp; MPI_Recv(&m, sizeof(my_struct), MPI_CHAR, 0, 0, MPI_COMM_WORLD,&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;MPI_STATUS_IGNORE);&nbsp; &nbsp; &nbsp; &nbsp; printf("%c %d %d\n", m.a, m.b, m.c);&nbsp;&nbsp; &nbsp; }&nbsp; &nbsp; MPI_Finalize();}由于C数组是连续存储数据的,所以我们甚至可以像构造m数组一样发送结构数组。因此,如果您有一个my_struct m_array[10],则可以发送(并以类似方式接收)MPI_Send(m_array, sizeof(my_struct) * 10, MPI_CHAR, 1, 0, MPI_COMM_WORLD);
打开App,查看更多内容
随时随地看视频慕课网APP