Mpi 测试或等待前的非阻塞通信缓冲区操作

Mpi 测试或等待前的非阻塞通信缓冲区操作,mpi,nonblocking,Mpi,Nonblocking,MPI标准规定,一旦为非阻塞通信功能提供了缓冲区,则在操作完成之前(即,在成功测试或等待功能之后),不允许应用程序使用该缓冲区 这是否也适用于以下情况: 我有一个缓冲区,缓冲区的每一部分都会进入不同的处理器,例如,缓冲区的一部分会从处理器本身的可用数据中复制 是否允许我在每个处理器上MPI\u Irecv从其他处理器复制缓冲区的不同部分,复制处理器中可用的部分,然后MPI\u发送应该发送给其他处理器的数据,执行我的其他计算,以及MPI\u Waitall以完成发送和接收 n=0; for (i

MPI标准规定,一旦为非阻塞通信功能提供了缓冲区,则在操作完成之前(即,在成功测试或等待功能之后),不允许应用程序使用该缓冲区

这是否也适用于以下情况:

我有一个缓冲区,缓冲区的每一部分都会进入不同的处理器,例如,缓冲区的一部分会从处理器本身的可用数据中复制

是否允许我在每个处理器上
MPI\u Irecv
从其他处理器复制缓冲区的不同部分,复制处理器中可用的部分,然后
MPI\u发送
应该发送给其他处理器的数据,执行我的其他计算,以及
MPI\u Waitall
以完成发送和接收

n=0;
for (i = 0; i < size; i++) {
    if (i != rank) {
        MPI_Irecv(&recvdata[i*100], 100, MPI_INT, i, i, comm, &requests[n]);
        n++;
    }
}

process(&recvdata[rank*100], 100);

for (i = 0; i < size; i++) {
    if (i != rank) { 
        MPI_Isend(&senddata[i*100], 100, MPI_INT, i, rank, comm, &requests[n]);
        n++;
    }
}

MPI_Waitall(n, requests, statuses);
n=0;
对于(i=0;i
我不能100%肯定我理解你的问题,所以我先重申一下这个问题:

如果我有一个大的数据数组,我可以创建非阻塞调用来接收来自数组子集的数据,然后将数据发送回其他进程吗

答案是肯定的,只要您在接收和发送之间同步。请记住,
MPI\u IRECV
中的数据在您使用
MPI\u WAIT
完成调用之前不会到达,因此在完成调用之前,您无法将其发送到其他进程。否则,发送将发送当时缓冲区中碰巧存在的任何垃圾

因此,您的代码可以如下所示,并且是安全的:

for (i = 0; i < size; i++)
    MPI_Irecv(&data[i*100], 100, MPI_INT, i, 0, comm, &requests[i]);

/* No touching data in here */

MPI_Waitall(i, requests, statuses);

/* You can touch data here */

for (i = 0; i < size; i++)
    MPI_Isend(&data[i*100], 100, MPI_INT, i+1, 0, comm); /* i+1 is wherever you want to send the data */

/* No touching data in here either */

MPI_Waitall(i, requests, statuses);
for(i=0;i
我不能100%肯定我理解你的问题,所以我先重申一下这个问题:

如果我有一个大的数据数组,我可以创建非阻塞调用来接收来自数组子集的数据,然后将数据发送回其他进程吗

答案是肯定的,只要您在接收和发送之间同步。请记住,
MPI\u IRECV
中的数据在您使用
MPI\u WAIT
完成调用之前不会到达,因此在完成调用之前,您无法将其发送到其他进程。否则,发送将发送当时缓冲区中碰巧存在的任何垃圾

因此,您的代码可以如下所示,并且是安全的:

for (i = 0; i < size; i++)
    MPI_Irecv(&data[i*100], 100, MPI_INT, i, 0, comm, &requests[i]);

/* No touching data in here */

MPI_Waitall(i, requests, statuses);

/* You can touch data here */

for (i = 0; i < size; i++)
    MPI_Isend(&data[i*100], 100, MPI_INT, i+1, 0, comm); /* i+1 is wherever you want to send the data */

/* No touching data in here either */

MPI_Waitall(i, requests, statuses);
for(i=0;i
在整个MPI标准中,使用术语位置,而不是术语变量,以防止此类混淆。只要未完成的MPI操作在不相交的内存位置集上运行,MPI库就不关心内存来自何处。不同的内存位置可能是一个大数组中的不同变量或不同元素。事实上,整个进程内存可以看作是一个巨大的匿名字节数组

在许多情况下,给定不同的变量声明集,可以实现相同的内存布局。例如,对于大多数x86/x64 C/C++编译器,以下两组局部变量声明将导致相同的堆栈布局:

inta,b;int d[3];
INTC;
|     ....     |      |     ....     |    |
+--------------+      +--------------+    |
|a | | d[2]||
+--------------++-------------+|低位地址
|b | | d[1]||
+--------------+      +--------------+    |
|c | | d[0]|\|/
+--------------++-------------+V
在这种情况下:

inta,b;
INTC;
MPI_Irecv(&a,1,MPI_INT,…,&req[0]);
MPI_Irecv(&c,1,MPI_INT,…,&req[1]);
MPI_Waitall(2,&req,MPI_状态\u忽略);
相当于:

intd[3];
MPI_Irecv(&d[2],1,MPI_INT,…,&req[0]);
MPI_Irecv(&d[0],1,MPI_INT,…,&req[1]);
MPI_Waitall(2,&req,MPI_状态\u忽略);
在第二种情况下,尽管
d[0]
d[2]
属于同一个变量,
&d[0]
&d[2]
指定了不同的和不相交的内存位置

在任何情况下,请确保您没有同时读取和写入同一内存位置

下面是Wesley Bland给出的示例的一个更复杂的版本。它通过使用
MPI_Waitsome
来重叠发送和接收操作:

MPI_请求rreqs[size],sreqs[size];
对于(i=0;i