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

时间:2015-05-15 16:40:26

标签: mpi nonblocking

MPI标准规定,一旦缓冲区被赋予非阻塞通信功能,在操作完成之前(即,直到成功的TEST或WAIT功能之后)才允许应用程序使用它。

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

我有一个缓冲区,其中的每一部分都将转到不同的处理器,例如,它的一部分将从处理器本身的可用数据中复制。

我是否允许每个处理器从其他处理器到MPI_Irecv缓冲区的不同部分,复制处理器中可用的部分,然后MPI_Isend应该发送给其他人的数据,进行其他计算,和MPI_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);

2 个答案:

答案 0 :(得分:4)

我不是百分百肯定我明白你在问什么,所以我先重述一下这个问题:

  

如果我有大量数据,是否可以创建非阻塞调用以从数组的子集接收数据,然后将数据发送回其他进程?

答案是肯定的,只要你在接收和发送之间进行同步。请注意,SELECT DISTINCT Recipes.name FROM Ingredients JOIN Contains USING(id_ingredient) JOIN Recipes USING (id_recipe) WHERE Ingredients.type = "bovin" AND Ingredients.type <> "lactic";中的数据在您使用MPI_IRECV完成调用之前不会到达,所以在发生这种情况之前,您无法将其发送到其他进程。否则,发送将发送当时缓冲区中的任何垃圾。

所以你的代码看起来像这样并且安全:

MPI_WAIT

答案 1 :(得分:3)

在整个MPI标准中,使用术语位置而不是术语变量以防止这种混淆。 MPI库并不关心内存来自何处,因为长时间未完成的MPI操作在不相交的内存位置上运行。不同的存储位置可以是不同的变量或大数组的不同元素。事实上,整个进程内存可以被认为是一个大的匿名字节数组。

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

int a, b;             int d[3];
int c;             

|     ....     |      |     ....     |    |
+--------------+      +--------------+    |
|      a       |      |     d[2]     |    |
+--------------+      +--------------+    |  lower addresses
|      b       |      |     d[1]     |    |
+--------------+      +--------------+    |
|      c       |      |     d[0]     |   \|/
+--------------+      +--------------+    V

在那种情况下:

int a, b;
int c;

MPI_Irecv(&a, 1, MPI_INT, ..., &req[0]);
MPI_Irecv(&c, 1, MPI_INT, ..., &req[1]);
MPI_Waitall(2, &req, MPI_STATUSES_IGNORE);

相当于:

int d[3];

MPI_Irecv(&d[2], 1, MPI_INT, ..., &req[0]);
MPI_Irecv(&d[0], 1, MPI_INT, ..., &req[1]);
MPI_Waitall(2, &req, MPI_STATUSES_IGNORE);

在第二种情况下,虽然d[0]d[2]属于同一个变量,但&d[0]&d[2]指定了不同的 - 并且与..., 1, MPI_INT, ...结合使用 - 不相交的记忆位置。

在任何情况下,请确保您没有同时读取和写入相同的存储位置。

Wesley Bland给出的一个更复杂的例子如下。它使用MPI_Waitsome代替发送和接收操作:

MPI_Request rreqs[size], sreqs[size];

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

while (1)
{
    int done_idx[size], numdone;

    MPI_Waitsome(size, rreqs, &numdone, done_idx, MPI_STATUSES_IGNORE);
    if (numdone == MPI_UNDEFINED)
        break;

    for (i = 0; i < numdone; i++)
    {
        int id = done_idx[i];
        process(&data[id*100], 100);
        MPI_Isend(&data[id*100], 100, MPI_INT, id, 0, comm, &sreqs[id]);
    }
}

MPI_Waitall(size, sreqs, MPI_STATUSES_IGNORE);

在这种特殊情况下,使用size单独的数组可能会导致代码更具可读性。