Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/67.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
MPI_Sendrecv_替换的替代方案_C_Mpi - Fatal编程技术网

MPI_Sendrecv_替换的替代方案

MPI_Sendrecv_替换的替代方案,c,mpi,C,Mpi,我正在尝试获得一个替代代码来 if(rank %2==0 && rightNeighbour != MPI_PROC_NULL) MPI_Sendrecv_replace(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, rightNeighbour, 1, MPI_COMM_WORLD, &status); else if(rank%2 ==1 &&

我正在尝试获得一个替代代码来

 if(rank %2==0 && rightNeighbour != MPI_PROC_NULL)
     MPI_Sendrecv_replace(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
                 rightNeighbour, 1, MPI_COMM_WORLD, &status);
 else if(rank%2 ==1 && leftNeighbour != MPI_PROC_NULL)
     MPI_Sendrecv_replace(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1, 
             leftNeighbour, 1, MPI_COMM_WORLD, &status);

 if (rank % 2 == 1 && rightNeighbour != MPI_PROC_NULL)  
    MPI_Sendrecv_replace(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1,
             rightNeighbour, 1, MPI_COMM_WORLD, &status);
 else if (rank % 2 == 0 && leftNeighbour != MPI_PROC_NULL)   
    MPI_Sendrecv_replace(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1, 
             leftNeighbour, 1, MPI_COMM_WORLD, &status);
使用
MPI\u-Send
MPI\u-Recv
但它似乎是死锁。使用
MPI\u Send
MPI\u Recv
有没有简单的方法可以实现同样的效果

我试过使用

if(rank %2==0 && rightNeighbour != MPI_PROC_NULL){
    MPI_Recv(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD, &status);

    MPI_Send(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD);
}

最好使用
MPI\u-Irecv
MPI\u-Isend
而不是阻塞调用(
MPI\u-Recv
MPI\u-Send
)。然后,在发出通信例程之后,只需使用
MPI_Waitall
等待请求(或两次调用
MPI_wait
)。但是,要做到这一点,您不能使用同一个缓冲区(即替换),您需要有两个单独的缓冲区,否则它们会损坏,因为缓冲区可能在实际发送之前替换内容

A
作为传入缓冲区,而
B
作为传出缓冲区,您的代码应该如下所示

if(rank %2==0 && rightNeighbour != MPI_PROC_NULL){
    MPI_Request req[2];
    MPI_Status status[2];

    MPI_Irecv (&A, len, MPI_DOUBLE, rightNeighbour, 1, 
      MPI_COMM_WORLD, &req[0]);
    MPI_Isend (&B, len, MPI_DOUBLE, rightNeighbour, 1, 
      MPI_COMM_WORLD, &req[1]);

    /* A */

    MPI_Waitall (2, req, status);
}

请注意,在
/*A*/
中,您可以利用通信飞行时进行一些计算。此外,代码中省略了错误检查——您最好检查MPI调用的所有返回代码。

您最好使用
MPI\u-Irecv
MPI\u-Isend
而不是阻塞调用(
MPI\u-Recv
MPI\u-Send
)。然后,在发出通信例程之后,只需使用
MPI_Waitall
等待请求(或两次调用
MPI_wait
)。但是,要做到这一点,您不能使用同一个缓冲区(即替换),您需要有两个单独的缓冲区,否则它们会损坏,因为缓冲区可能在实际发送之前替换内容

A
作为传入缓冲区,而
B
作为传出缓冲区,您的代码应该如下所示

if(rank %2==0 && rightNeighbour != MPI_PROC_NULL){
    MPI_Request req[2];
    MPI_Status status[2];

    MPI_Irecv (&A, len, MPI_DOUBLE, rightNeighbour, 1, 
      MPI_COMM_WORLD, &req[0]);
    MPI_Isend (&B, len, MPI_DOUBLE, rightNeighbour, 1, 
      MPI_COMM_WORLD, &req[1]);

    /* A */

    MPI_Waitall (2, req, status);
}
请注意,在
/*A*/
中,您可以利用通信飞行时进行一些计算。此外,代码中省略了错误检查——您最好检查MPI调用的所有返回代码。

此代码:

if(rank % 2 == 0 && rightNeighbour != MPI_PROC_NULL)
   MPI_Sendrecv_replace(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
                       rightNeighbour, 1, MPI_COMM_WORLD, &status);
else if(rank % 2 == 1 && leftNeighbour != MPI_PROC_NULL)
   MPI_Sendrecv_replace(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1, 
                        leftNeighbour, 1, MPI_COMM_WORLD, &status);
相当于:

if(rank % 2 == 0)
{
   MPI_Send(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1,
            MPI_COMM_WORLD);
   MPI_Recv(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1,
            MPI_COMM_WORLD, &status);
}
else if(rank % 2 == 1)
{
   double *temp = malloc(len * sizeof(double));
   MPI_Recv(temp, len, MPI_DOUBLE, leftNeighbour, 1,
            MPI_COMM_WORLD, &status);
   MPI_Send(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1,
            MPI_COMM_WORLD, &status);
   memcpy(&bufferLeft[0], temp, len * sizeof(double));
   free(temp);
}
请注意,发送和接收呼叫的顺序在奇数列中是相反的。此外,接收使用临时缓冲区来实现
MPI\u Sendrecv\u replace
的语义,该语义保证首先发送缓冲区中的数据,然后才用接收到的数据覆盖

请注意,检查列组是否不是
MPI\u PROC\u NULL
是毫无意义的,因为从
MPI\u PROC\u NULL
发送到/接收基本上是无操作的,并且总是成功的。
MPI\u PROC\u NULL
语义的一个关键思想是,如果,则有助于编写不包含此类
的对称代码。

此代码:

if(rank % 2 == 0 && rightNeighbour != MPI_PROC_NULL)
   MPI_Sendrecv_replace(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
                       rightNeighbour, 1, MPI_COMM_WORLD, &status);
else if(rank % 2 == 1 && leftNeighbour != MPI_PROC_NULL)
   MPI_Sendrecv_replace(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1, 
                        leftNeighbour, 1, MPI_COMM_WORLD, &status);
相当于:

if(rank % 2 == 0)
{
   MPI_Send(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1,
            MPI_COMM_WORLD);
   MPI_Recv(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1,
            MPI_COMM_WORLD, &status);
}
else if(rank % 2 == 1)
{
   double *temp = malloc(len * sizeof(double));
   MPI_Recv(temp, len, MPI_DOUBLE, leftNeighbour, 1,
            MPI_COMM_WORLD, &status);
   MPI_Send(&bufferLeft[0], len, MPI_DOUBLE, leftNeighbour, 1,
            MPI_COMM_WORLD, &status);
   memcpy(&bufferLeft[0], temp, len * sizeof(double));
   free(temp);
}
请注意,发送和接收呼叫的顺序在奇数列中是相反的。此外,接收使用临时缓冲区来实现
MPI\u Sendrecv\u replace
的语义,该语义保证首先发送缓冲区中的数据,然后才用接收到的数据覆盖


请注意,检查列组是否不是
MPI\u PROC\u NULL
是毫无意义的,因为从
MPI\u PROC\u NULL
发送到/接收基本上是无操作的,并且总是成功的。
MPI_PROC_NULL
语义的一个关键思想是,如果
的话,可以方便地编写不包含此类
的对称代码。

尽管最好的方法可能是遵循Harald关于使用
MPI Isend
MPI Irecv
的建议,根据具体情况,有一种选择可能不起作用

对于较小的缓冲区大小,一些MPI实现遵循所谓的“急切模式”。在这种模式下,无论接收者是否已经在等待消息,都会发送消息。发送缓冲区数据被复制到临时缓冲区,由于用户的发送缓冲区在复制完成后可用,
MPI_send
在通信实际完成之前返回

这有点冒险,因为对于大型消息,MPI通常在会合模式下工作,这实际上会同步两端,因此以下代码也会产生死锁:

if(rank %2==0 && rightNeighbour != MPI_PROC_NULL){

    MPI_Send(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD);

    MPI_Recv(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD, &status);
}
然而,在
MPI_Recv
中,接收缓冲区(显然)在数据接收之前不可用


有关的其他信息。

尽管最好的方法可能是遵循Harald关于使用
MPI Isend
MPI Irecv
的建议,但根据具体情况,有一种方法可能不起作用

对于较小的缓冲区大小,一些MPI实现遵循所谓的“急切模式”。在这种模式下,无论接收者是否已经在等待消息,都会发送消息。发送缓冲区数据被复制到临时缓冲区,由于用户的发送缓冲区在复制完成后可用,
MPI_send
在通信实际完成之前返回

这有点冒险,因为对于大型消息,MPI通常在会合模式下工作,这实际上会同步两端,因此以下代码也会产生死锁:

if(rank %2==0 && rightNeighbour != MPI_PROC_NULL){

    MPI_Send(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD);

    MPI_Recv(&bufferRight[0], len, MPI_DOUBLE, rightNeighbour, 1, 
         MPI_COMM_WORLD, &status);
}
然而,在
MPI_Recv
中,接收缓冲区(显然)在数据接收之前不可用


有关的其他信息。

@\hr当
(秩%2==0)
时,您为什么不使用临时缓冲区?@Manolete:因为
MPI\u Send
是一个阻塞操作-它仅在缓冲区的内容被MPI消耗后返回,因此将同一缓冲区传递给
MPI\u Recv
是安全的,这将覆盖以前的内容。@_hr当
(秩%2==0)
时,为什么不使用临时缓冲区?@Manolete:因为
MPI\u Send
是一个阻塞操作-它只在