我正在尝试无序地进行一对一的通信。基本上我有多个相同大小的浮点数组,由整数id标识。
每封邮件应如下所示:
<int id><float array data>
在接收器端,它确切知道有多少阵列,因此设置了确切的recv数。收到消息后,它会解析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进行计算。
答案 0 :(得分:3)
您可以在接收函数中指定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();
}
答案 1 :(得分:3)
正如某人已经写过的那样,您可以使用MPI_ANY_SOURCE
从任何来源接收。要在一次发送中发送两种不同类型的数据,您可以使用derived datatype:
#include <stdio.h>
#include <stdlib.h>
#include "mpi.h"
#define asize 10
typedef struct data_ {
int id;
float array[asize];
} data;
int main() {
MPI_Init(NULL,NULL);
int rank = -1;
int size = -1;
MPI_Comm_rank(MPI_COMM_WORLD,&rank);
MPI_Comm_size(MPI_COMM_WORLD,&size);
data buffer;
// Define and commit a new datatype
int blocklength [2];
MPI_Aint displacement[2];
MPI_Datatype datatypes [2];
MPI_Datatype mpi_tdata;
MPI_Aint startid,startarray;
MPI_Get_address(&(buffer.id),&startid);
MPI_Get_address(&(buffer.array[0]),&startarray);
blocklength [0] = 1;
blocklength [1] = asize;
displacement[0] = 0;
displacement[1] = startarray - startid;
datatypes [0] = MPI_INT;
datatypes [1] = MPI_FLOAT;
MPI_Type_create_struct(2,blocklength,displacement,datatypes,&mpi_tdata);
MPI_Type_commit(&mpi_tdata);
if (rank == 0) {
int count = 0;
MPI_Status status;
while (count < size-1 ) {
// Non-blocking receive
printf("Receiving message %d\n",count);
MPI_Recv(&buffer,1,mpi_tdata,MPI_ANY_SOURCE,0,MPI_COMM_WORLD,&status);
printf("Message tag %d, first entry %g\n",buffer.id,buffer.array[0]);
// Counting the received messages
count++;
}
} else {
// Initialize buffer to be sent
buffer.id = rank;
for (int ii = 0; ii < size; ii++) {
buffer.array[ii] = 10*rank + ii;
}
// Send buffer
MPI_Send(&buffer,1,mpi_tdata,0,0,MPI_COMM_WORLD);
}
MPI_Type_free(&mpi_tdata);
MPI_Finalize();
return 0;
}