使用MPI_Send和MPI_Recv发送大型std::vector不';不完整

使用MPI_Send和MPI_Recv发送大型std::vector不';不完整,mpi,stdvector,Mpi,Stdvector,我正在尝试使用MPI发送std::vector。当向量很小时,这可以很好地工作,但当向量很大时(向量中超过~15k倍)就不起作用。当试图发送一个20k双倍的向量时,程序只是在CPU为100%的情况下运行 这里有一个最小的例子 #include <vector> #include <mpi.h> using namespace std; vector<double> send_and_receive(vector<double> &loc

我正在尝试使用MPI发送std::vector。当向量很小时,这可以很好地工作,但当向量很大时(向量中超过~15k倍)就不起作用。当试图发送一个20k双倍的向量时,程序只是在CPU为100%的情况下运行

这里有一个最小的例子

#include <vector>
#include <mpi.h>

using namespace std;

vector<double> send_and_receive(vector<double> &local_data, int n, int numprocs, int my_rank) {
    MPI_Send(&local_data[0], n, MPI_DOUBLE, 0, 0, MPI_COMM_WORLD);

    if (my_rank == 0) {
        vector<double> global_data(numprocs*n);
        vector<double> temp(n);
        for (int rank = 0; rank < numprocs; rank++) {
            MPI_Recv(&temp[0], n, MPI_DOUBLE, rank, 0, MPI_COMM_WORLD, MPI_STATUS_IGNORE);
            for (int i = 0; i < n; i++) {
                global_data[rank*n + i] = temp[i];
            }
        }
        return global_data;
    }
    return vector<double>();
}

int main(int args, char *argv[]) {
    int my_rank, numprocs;
    // MPI initialization
    MPI_Init (&args, &argv);
    MPI_Comm_rank (MPI_COMM_WORLD, &my_rank);
    MPI_Comm_size (MPI_COMM_WORLD, &numprocs);

    int n = 15000;
    vector<double> local_data(n);

    for (int i = 0; i < n; i++) {
        local_data[i] = n*my_rank + i;
    }

    vector<double> global_data = send_and_receive(local_data, n, numprocs, my_rank);

    MPI_Finalize();

    return 0;
}
并使用

mpirun -n 2 a.out
当我用
n=15000
运行时,程序成功完成,但用
n=17000
n=20000
运行时,它永远不会完成,两个CPU的运行率为100%,直到我强制关闭程序


有人知道问题出在哪里吗?

MPI\u Send
是一个有趣的电话。如果有足够的内部缓冲区来存储输入,它可能会返回—它所做的唯一保证是MPI不再需要输入缓冲区。但是,如果没有足够的内部缓冲区空间,调用将阻塞,直到相反的
MPI_Recv
调用开始接收数据。看看这是怎么回事?由于缓冲区空间不足,这两个进程都会发送该块。当调试类似的问题时,将
MPI\u Send
替换为
MPI\u Send

您可能的解决方案是:

  • 使用缓冲发送,
    MPI\u Bsend
  • 使用
    MPI\u Sendrecv
  • 备用发送/接收对,以便每个发送都有一个匹配的接收(例如,奇数proc发送,偶数recv,反之亦然)
  • 使用非阻塞发送,
    MPI\u Isend

请参见

非常感谢,我刚才正在查看Isend/Irecv。如果我只是在示例中使用Isend和Irecv,我是否应该在接收之前添加
MPI\u屏障(MPI\u COMM\u WORLD)
?不需要Irecv,您只需要发送返回即可。也不需要障碍物。
mpirun -n 2 a.out