如何使用结构指针数组 MPI 发送和接收嵌套结构?
How to MPI Send and Recv Nested struct with Pointer Array of Struct?
下面是结构声明和代码:
struct cell_struct {
int x, y;
bool isWater, isPort, isRock;
struct port_struct port_data;
struct ship_struct *ships_data[MAX_SHIPS_PER_CELL];
int number_ships;
};
struct ship_struct {
int route, totalHoursAtSea, hoursAtSeaThisJourney, id, numberPassengers, euclideanPlannedDistance;
bool willMoveThisTimestep;
};
// Data associated with each port
struct port_struct {
int shipsInPastHundredHours[10];
int port_index, passengersShipped;
double totalFeesCollected;
};
struct cell_struct *domain_test;
domain_test = (struct cell_struct *) malloc(
sizeof(struct cell_struct) * (mpi_info->local_size_x + 2) * simulation_configuration->size_y);
使用下面的 Send 和 Recv,我能够发送和接收,domain_test,但在发送和接收后无法从 domain_test 访问 ships_data。有什么帮助吗?
MPI_Send(&domain_test[mpi_info->local_size_x_end * simulation_configuration->size_y + i], sizeof(struct cell_struct), MPI_BYTE, 1, i, MPI_COMM_WORLD);
MPI_Recv(&domain_test[0],sizeof(struct cell_struct) * simulation_configuration->size_y, MPI_BYTE, 0, 0, MPI_COMM_WORLD, &status);
您的代码中的主要问题是 cell_struct
存储了一个静态数组 指向船舶 的指针,这意味着船舶本身的数据可能到处都是这个地方。如果您改为存储船舶的静态数组,,您将有一个连续的内存块需要发送。您甚至可以使用 count=sizeof(cell_struct)
和 type=MPI_BYTE
然后(就像您现在所做的那样)或@Gilles 指示的任何方法发送它。
您的代码的结果是现在在分配给单元格时会复制飞船,而不仅仅是设置指针。如果船只的数据很少,这不是问题,如此处所示,但如果复制成本很高,可能会使代码变慢。
对于系统之间复杂数据结构的传输,如果您不希望按照 Jonas 的建议将结构安排为一个连续的内存块,那么这就是某种形式的序列化发挥作用的地方。
对于 C 编程语言,要使用序列化技术,您几乎必须坚持模式优先,例如 Google 协议缓冲区(请参阅 C version and Google's page)。 Java 和 C# 等其他语言内置了序列化功能,因此您可以选择代码优先或模式优先序列化。
最简短的概述是:
- 编写描述数据结构的模式文件(GPB 的 .proto),就像在 C 中使用 struct{} 定义一样
- 使用提供的工具编译模式以输出确实使用 struct{} 定义数据结构的 C 代码,以及一组可以将它们序列化/反序列化为线格式的函数
- 在您的项目中使用生成的 C 代码。您使用生成的结构根据需要声明变量,并使用序列化/反序列化函数生成/消耗 MPI_BYTE 缓冲区,
- 您使用 MPI
发送/接收这些 MPI_BYTE 缓冲区
这有一些基本的优点:
- 您的分布式系统可以是异构的。因此,不必在 PC 上使用 64 位 C 运行ning 运行ning Windows 10 64 位在任何地方都使用相同的编译器编译,您可以混合搭配语言、机器类型、操作系统、编译器等;
- 您可以合理安排数据结构,而不是为了在连续内存中实现存储而使它们更加模糊。
我的猜测是,如果您为了发送/接收数据而重新安排内存以构建/解构连续内存,您会更好(从 运行 时间长度点开始的观点)与像 GPB 这样的序列化技术。
下面是结构声明和代码:
struct cell_struct {
int x, y;
bool isWater, isPort, isRock;
struct port_struct port_data;
struct ship_struct *ships_data[MAX_SHIPS_PER_CELL];
int number_ships;
};
struct ship_struct {
int route, totalHoursAtSea, hoursAtSeaThisJourney, id, numberPassengers, euclideanPlannedDistance;
bool willMoveThisTimestep;
};
// Data associated with each port
struct port_struct {
int shipsInPastHundredHours[10];
int port_index, passengersShipped;
double totalFeesCollected;
};
struct cell_struct *domain_test;
domain_test = (struct cell_struct *) malloc(
sizeof(struct cell_struct) * (mpi_info->local_size_x + 2) * simulation_configuration->size_y);
使用下面的 Send 和 Recv,我能够发送和接收,domain_test,但在发送和接收后无法从 domain_test 访问 ships_data。有什么帮助吗?
MPI_Send(&domain_test[mpi_info->local_size_x_end * simulation_configuration->size_y + i], sizeof(struct cell_struct), MPI_BYTE, 1, i, MPI_COMM_WORLD);
MPI_Recv(&domain_test[0],sizeof(struct cell_struct) * simulation_configuration->size_y, MPI_BYTE, 0, 0, MPI_COMM_WORLD, &status);
您的代码中的主要问题是 cell_struct
存储了一个静态数组 指向船舶 的指针,这意味着船舶本身的数据可能到处都是这个地方。如果您改为存储船舶的静态数组,count=sizeof(cell_struct)
和 type=MPI_BYTE
然后(就像您现在所做的那样)或@Gilles 指示的任何方法发送它。
您的代码的结果是现在在分配给单元格时会复制飞船,而不仅仅是设置指针。如果船只的数据很少,这不是问题,如此处所示,但如果复制成本很高,可能会使代码变慢。
对于系统之间复杂数据结构的传输,如果您不希望按照 Jonas 的建议将结构安排为一个连续的内存块,那么这就是某种形式的序列化发挥作用的地方。
对于 C 编程语言,要使用序列化技术,您几乎必须坚持模式优先,例如 Google 协议缓冲区(请参阅 C version and Google's page)。 Java 和 C# 等其他语言内置了序列化功能,因此您可以选择代码优先或模式优先序列化。
最简短的概述是:
- 编写描述数据结构的模式文件(GPB 的 .proto),就像在 C 中使用 struct{} 定义一样
- 使用提供的工具编译模式以输出确实使用 struct{} 定义数据结构的 C 代码,以及一组可以将它们序列化/反序列化为线格式的函数
- 在您的项目中使用生成的 C 代码。您使用生成的结构根据需要声明变量,并使用序列化/反序列化函数生成/消耗 MPI_BYTE 缓冲区,
- 您使用 MPI 发送/接收这些 MPI_BYTE 缓冲区
这有一些基本的优点:
- 您的分布式系统可以是异构的。因此,不必在 PC 上使用 64 位 C 运行ning 运行ning Windows 10 64 位在任何地方都使用相同的编译器编译,您可以混合搭配语言、机器类型、操作系统、编译器等;
- 您可以合理安排数据结构,而不是为了在连续内存中实现存储而使它们更加模糊。
我的猜测是,如果您为了发送/接收数据而重新安排内存以构建/解构连续内存,您会更好(从 运行 时间长度点开始的观点)与像 GPB 这样的序列化技术。