简体   繁体   English

在for循环中使用MPI_Irecv和MPI_Isend

[英]Using MPI_Irecv and MPI_Isend in a for loop

I have an issue with MPI_Isend and MPI_Irecv . 我有MPI_IsendMPI_Irecv的问题。 I am working on an adjacency matrix of a graph, which is distributed row-wise. 我正在研究图的邻接矩阵,该矩阵按行分布。 We can assume each processor contains one row. 我们可以假设每个处理器包含一行。 For each pair of indices (i,j) I need to send and receive 2 integers. 对于每对索引(i,j)我需要发送和接收2个整数。 Basically, I need to receive some other information from the other rows in order to do computations. 基本上,我需要从其他行接收一些其他信息以便进行计算。 I am new in MPI, and here it goes into infinite loop, I am not sure even is it the right way of using MPI_Isend or MPI_Irecv in a for loop, also the place of putting wait. 我是MPI的新手,它进入了无限循环,我不确定即使是在for循环中使用MPI_IsendMPI_Irecv的正确方法,也不确定是否需要等待。

As an example, Assume we have we have a graph with 6 vertices, and so the adjacency matrix ( adjMatrix ) will be a 6*6 matrix, we also have a 6*2 matrix for some other information, and finally, we distribute the data among 6 processors. 例如,假设我们有一个具有6个顶点的图,因此邻接矩阵( adjMatrix )将为6 * 6矩阵,对于其他信息,我们还将有6 * 2矩阵,最后,我们将6个处理器之间的数据。 Therefore: 因此:

          |0  20 16 0  6  0 |      |0  1|
          |20 0  0  19 0  6 |      |1  1|
addMatrix=|16 0  0  0  12 0 |    M=|2  1|
          |0  19 0  0  0  12|      |3  1|
          |6  0  12 0  0  9 |      |0  0|
          |0  6  0  12 9  0 |      |1  0|

We distribute the matrices as follows: 我们按如下方式分配矩阵:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|

P2:       |16 0  0  0  12 0 |      |2  1|

P3:       |0  19 0  0  0  12|      |3  1|

P4:       |6  0  12 0  0  9 |      |0  0|

P5:       |0  6  0  12 9  0 |      |1  0|

Now, each processor needs to update its portion of adjMatrix . 现在,每个处理器都需要更新其adjMatrix部分。 To do so, they need information from some portion of the matrix M , which is in the other processors. 为此,他们需要来自其他处理器中矩阵M某些部分的信息。 For example, in order to P0 updates index (0,1) which is 20 , it needs to have access to the row 1 of matrix M which is {1,1} . 例如,为了P0更新索引(0,1)20 ,它需要访问矩阵M的第1行,即{1,1} Therefore: 因此:

P1 should send MLocal[0][0]=1 and MLocal[0][1]=1 to P0 in which P0 receives them as M_j0 and M_j1 , respectively. P1应该将MLocal[0][0]=1MLocal[0][1]=1发送到P0 ,其中P0分别将它们作为M_j0M_j1接收。

And

P0 should send MLocal[0][0]=0 and MLocal[0][1]=1 to P1 in which P1 receives them as M_j0 and M_j1 , respectively. P0应该将MLocal[0][0]=0MLocal[0][1]=1发送到P1 ,其中P1分别将它们作为M_j0M_j1接收。

    for(int i=0;i<rows;i++){
            for (int j=0; j<n; j++)
            {
                int M_j0,M_j1;
                MPI_Isend(&MLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &send_request0);
                MPI_Isend(&MLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &send_request1);
                MPI_Irecv(&M_j0, 1, MPI_INT, j, my_rank+i*n+j+0, MPI_COMM_WORLD, &recv_request0);
                MPI_Irecv(&M_j1, 1, MPI_INT, j, my_rank+i*n+j+1, MPI_COMM_WORLD, &recv_request1);
                //MPI_Wait(&send_request0, &status);
                //MPI_Wait(&send_request1, &status);
                MPI_Wait(&recv_request0, &status);
                MPI_Wait(&recv_request1, &status);

                 // Do something ...
            }
        }

Then with GillesGouaillardet suggestion, I changed that 4 MPI_Isend and MPI_Irecv to: 然后用GillesGouaillardet建议,我改变了4 MPI_IsendMPI_Irecv到:

    MPI_Sendrecv(&MoatsLocal[i][0], 1, MPI_INT, j, my_rank+i*n+j+0, &M_j0,1, MPI_INT, my_rank, my_rank+i*n+j+0, MPI_COMM_WORLD, &status);
    MPI_Sendrecv(&MoatsLocal[i][1], 1, MPI_INT, j, my_rank+i*n+j+1, &M_j1,1, MPI_INT, my_rank, my_rank+i*n+j+1, MPI_COMM_WORLD, &status);

But still, it goes into an infinite loop. 但是,它仍然进入无限循环。

UPDATE: 更新:

I updated the code, some part of the issue was because of the processors ranking and matching the tags. 我更新了代码,部分原因是因为处理器对标签进行排名和匹配。 I fixed that part but still, it had deadlock prone, which I think I know where is the problem. 我修复了该部分,但仍然容易出现死锁,我想我知道问题出在哪里。 And might not be able to solve it. 并且可能无法解决它。 If I had enough number of processors, to distribute each line to a processor, ie n=p, it would not be any issues. 如果我有足够数量的处理器,可以将每行分配给一个处理器,即n = p,那么就不会有任何问题。 But the issue is where the number of processors is less than n , then the flow is not nicely through the main diagonal I explain it through the example, let us assume we have 4 processors and n=6 . 但是问题是处理器的数量小于n ,那么通过主对角线的流程不是很好,我通过示例进行了解释,让我们假设我们有4个处理器, n=6 Assume here is the distribution: 假设这里是分布:

P0:       |0  20 16 0  6  0 |      |0  1|

P1:       |20 0  0  19 0  6 |      |1  1|
          |16 0  0  0  12 0 |      |2  1|

P2:       |0  19 0  0  0  12|      |3  1|

P3:       |6  0  12 0  0  9 |      |0  0|
          |0  6  0  12 9  0 |      |1  0|

This is what is happing through the loop. 这就是循环中的内容。

The first iteration: 第一次迭代:

P0 send and receive to/from P1 information for (0,1):"20" and wait(done) P0向P1发送和从P1接收以下信息:(0,1):“ 20”并等待(完成)

P1 send and receive to/from P0 information for (1,0):"20" and wait(done) P1向P0发送和从P0接收/接收(1,0)的信息:“ 20”并等待(完成)

P2 send and receive to/from P1 information for (3,1):"19" and wait P2向P1发送和从P1接收(3,1):“ 19”的信息,然后等待

P3 send and receive to/from P0 information for (4,1):"6" and wait P3向P0发送和从P0接收(4,1):“ 6”的信息,然后等待

Second iteration: 第二次迭代:

P0 send and receive to/from P1 information for (0,2):"16" and wait P0向P1发送和从P1接收(0,2)的信息:“ 16”并等待

P1 send and receive to/from P2 information for (1,3):"19" and wait(done) P1向P2发送和从P2接收(1,3)的信息:“ 19”并等待(完成)

P2 was wainting for P1 (3,1):"19" then just recieved it and done! P2正在为P1(3,1)哀哭:“ 19”,然后就收到并完成了!

P3 is waiting for P0 for (4,1):"6" and wait P3正在等待P0(4,1):“ 6”并等待

Third iteration: 第三次迭代:

P0 is waiting for P1 for (0,2):"16" P0正在等待P1(0,2):“ 16”

P1 send and receive to/from P3 information for (1,5):"19" and wait P1向P3发送和从(3,5):“ 19”接收信息,然后等待

P2 send and receive to/from P3 information for (3,5):"12" and wait P2向P3发送和从P3发送和接收(3,5):“ 12”的信息,然后等待

P3 is waiting for P0 for (4,1):"6" P3正在等待P0(4,1):“ 6”

Forth iteration: 第四次迭代:

P0 is waiting for P1 for (0,2):"16" P0正在等待P1(0,2):“ 16”

P1 is waiting for P3 for (1,5):"19" P1正在等待P3的(1,5):“ 19”

P2 is waiting for P3 for (3,5):"12" P2正在等待P3(3,5):“ 12”

P3 is waiting for P0 for (4,1):"6" P3正在等待P0(4,1):“ 6”

Now, all are waiting for each other, I do not think there is any way to solve it. 现在,所有人都在等待对方,我认为没有任何办法可以解决它。 The solution that ptb suggested might work, I will try that one. ptb建议的解决方案可能会起作用,我将尝试该解决方案。

Still, any other idea is appreciated! 尽管如此,任何其他想法还是值得赞赏的!

There are a few issues with the code you posted 您发布的代码存在一些问题

  1. Each processor will loop through rows . 每个处理器将遍历rows However In your description, the rows are distributed among the processors so this is probably an error. 但是,在您的描述中,行在处理器之间分布,因此这可能是错误的。
  2. The send and recv destination and sources are identical. 发送和接收的目的地和源是相同的。 So if you consider the case when j=0 , MPI_Isend(...,j,...) means every rank will send something to the root process. 因此,如果考虑j=0的情况,MPI_Isend(...,j,...)意味着每个等级都会向根进程发送一些信息。 This is followed by a call to MPI_IRecv(...,j,...), MPI_Wait which means that every process will wait for a send from the root process which never comes. 接下来是对MPI_IRecv(...,j,...),MPI_Wait的调用,这意味着每个进程都将等待来自根进程的发送,而该发送永远不会进行。
  3. The MPI_SendRecv call has the same fundamental problem MPI_SendRecv调用具有相同的基本问题

The challenge is that you need your send and recv calls to match up. 挑战在于您需要发送和接收调用来匹配。 One way to do that (not necessarily the most performant) would be to post all your sends via MPI_Isend in a loop and then use MPI_Probe, MPI_Recv to process each ranks recvs (since the number of recvs is the number of sends you know exactly how many). 一种方法(不一定是性能最高的方法)是将所有通过MPI_Isend发送的发送都循环发送,然后使用MPI_Probe,MPI_Recv处理每个等级的接收(因为接收的数量就是发送的数量,您确切知道如何许多)。 A pseudo code example: 伪代码示例:

int send_count = 0;
for (int j=0; j<n; j++) {
  if (matrix_entry[j] != 0) {
    call MPI_Isend(M_local, 2, MPI_INT, j, 0, ...)
    send_count++;
  }
}
while (send_count) {
  MPI_Probe(MPI_ANY_SOURCE, MPI_ANY_TAG, comm, status)
  /* get source from status and then call recv */
  MPI_Recv(M_j01, 2, MPI_INTEGER, status(MPI_SOURCE), ...)
 /* Do something with M_j01 */
 send_count--;
} 

Some little advises: 一些小建议:

You always have to remember that each process are independent.. There is no synchronization between processes (expect if you put a MPI_Barrier). 您始终必须记住每个进程都是独立的。进程之间没有同步(请注意是否放置了MPI_Barrier)。

I really do not understand your loop over rows (does rows = 6?) 我真的不理解您的行循环(行= 6吗?)

Then all processes execute the code.... This means: P0,1,2,3,4,5,6 Calls yours sendrecv, all of them does it 6 times, as those calls are in a loop... 然后所有进程都执行该代码。...这意味着:P0,1,2,3,4,5,6调用您的sendrecv,它们都执行了6次,因为这些调用都处于循环中...

Finally: What would be the usual size of the matrix? 最后:矩阵的通常大小是多少? It is a really bad idea to send lot of very small messages. 发送很多非常小的消息是一个非常糟糕的主意。

You should design your algorithm as follow: 1) Figure out which data the process PX needs to update all its column. 您应该按照以下步骤设计算法:1)找出流程PX更新其所有列所需的数据。 2) perform communication which gather this data for all processes 3) Perform the update. 2)执行收集所有进程此数据的通信3)执行更新。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM