我正在尝试乱序进行一对一通信。基本上我有多个相同大小的 float 组,由整数 id 标识。
每条消息应该如下所示:
<int id><float array data>
在接收方,它确切地知道有多少个数组,因此设置了准确的接收数。收到消息后,它会解析 id 并将数据放入正确的位置。问题是消息可以从任何其他进程发送到接收进程。 (例如,生产者有一个工作队列结构,并处理队列中可用的任何 id。)
由于 MPI 只保证 P2P 顺序传递,我不能简单地将整数 id 和 FP 数据放在两个消息中,否则接收方可能无法将 id 与数据匹配。 MPI 也不允许一次发送两种类型的数据。
我只能想到两种方法。
1) 接收方有一个大小为 m (source[m]) 的数组,m 是发送节点的数量。发件人先发送id,然后发送数据。接收方在收到来自发送方 i 的整数消息后将 id 保存到 source[i]。从发送者 i 接收到 FP 数组后,它检查 source[i],获取 id,并将数据移动到正确的位置。它之所以有效,是因为 MPI 保证了有序的 P2P 通信。它要求接收方为每个发送方保留状态信息。更糟糕的是,如果单个发送进程可以在数据之前发送两个 id(例如多线程),则该机制将不起作用。
2) 将 id 和 FP 视为字节,并将它们复制到发送缓冲区中。将它们作为 MPI_CHAR 发送,接收方将它们转换回整数和 FP 数组。然后我需要支付将东西复制到发送方字节缓冲区的额外费用。随着 MPI 进程中线程数量的增加,总临时缓冲区也会增加。
它们都不是完美的解决方案。我不想在进程中锁定任何东西。不知道大家有没有更好的建议。
编辑:代码将在带有 infiniband 的共享集群上运行。这些机器将被随机分配。所以我不认为 TCP 套接字能够在这里帮助我。另外,IPoIB 看起来很贵。我确实需要完整的 40Gbps 通信速度,并让 CPU 继续进行计算。
最佳答案
您可以在接收函数中指定 MPI_ANY_SOURCE
作为源排名,然后使用它们的标签对消息进行排序,这比创建自定义消息更容易。这是一个简化的示例:
#include <stdio.h>
#include "mpi.h"
int main() {
MPI_Init(NULL,NULL);
int rank=0;
int size=1;
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
// Receiver is the last node for simplicity in the arrays
if (rank == size-1) {
// Receiver has size-1 slots
float data[size-1];
MPI_Request request[size-1];
// Use tags to sort receives
for (int tag=0;tag<size-1;++tag){
printf("Receiver for id %d\n",tag);
// Non-blocking receive
MPI_Irecv(data+tag,1,MPI_FLOAT,
MPI_ANY_SOURCE,tag,MPI_COMM_WORLD,&request[tag]);
}
// Wait for all requests to complete
printf("Waiting...\n");
MPI_Waitall(size-1,request,MPI_STATUSES_IGNORE);
for (size_t i=0;i<size-1;++i){
printf("%f\n",data[i]);
}
} else {
// Producer
int id = rank;
float data = rank;
printf("Sending {%d}{%f}\n",id,data);
MPI_Send(&data,1,MPI_FLOAT,size-1,id,MPI_COMM_WORLD);
}
return MPI_Finalize();
}
关于c++ - 我可以捆绑两个 MPI 消息吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12701393/