简单的你好世界非阻塞 MPI
Simple hello world non blocking MPI
我正在使用 this website 练习一个简单的非阻塞“Hello world”程序。
#include <iostream>
#include <mpi.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Request request;
MPI_Status status;
int size, rank, data;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank>0) {
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
<< std::endl;
}
std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;
data=rank;
MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);
MPI_Finalize();
return 0;
}
我有几个问题:第一个是 (rank + 1) % size
对我来说没有意义。我希望这只是 rank+1
而不是 (rank + 1) % size
。但是,当我删除 %size
时,代码不会 运行。我的第二个歧义是这个特定代码的结果:
#PTP job_id=12493
Rank 3 has received message with data 21848 from rank 2
Hello from rank 3 out of 4
Hello from rank 0 out of 4
Rank 2 has received message with data 22065 from rank 1
Hello from rank 2 out of 4
Rank 1 has received message with data 22043 from rank 0
Hello from rank 1 out of 4
我已将数据定义为等于等级,但它似乎随机抛出一些东西。这是为什么?
TL;DR 您代码中的主要问题(很可能)是数据显示随机值的原因是 MPI_Irecv
和 MPI_Isend
的使用没有MPI_Wait
(或MPI_Test
)的调用。
MPI_Irecv and MPI_Isend are nonblocking communication routines, therefore one needs to use the MPI_Wait (or use MPI_Test测试请求是否完成)确保消息完成,send/receive缓冲区中的数据可以再次安全 操纵。
让我们想象一下,您使用 MPI_Isend
发送一个整数数组而不调用 MPI_Wait
;在这种情况下,您不确定何时可以安全地修改(或取消分配)该数组的内存。 MPI_Irecv
也是如此。尽管如此,调用 MPI_Wait
可确保从那一点开始 read/write (或释放内存)缓冲区没有 undefined behavior 或不一致数据的风险。
在MPI_Isend
期间必须读取和发送缓冲区的内容(例如整数数组);同样,在 MPI_Irecv
期间,接收缓冲区的内容必须到达。同时,可以与正在进行的过程重叠一些计算,但是这个计算不能改变(或读取)send/recv 缓冲区的内容。 然后调用 MPI_Wait
以确保从那时起数据 send/recv 可以安全地 read/modified 没有任何问题。
在您的代码中,无论您如何调用:
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
之后不调用 MPI_Wait
。此外,您更改缓冲区的内容 ,即 data=rank
;。如前所述,这可能导致 未定义的行为 。
您可以通过使用 MPI_Recv and MPI_Send 或调用 MPI_Irecv
和 MPI_Isend
然后调用 MPI_Wait
来解决这个问题。从语义上讲,调用 MPI_Isend()
后调用 MPI_Wait()
或调用 MPI_Recv
后调用 MPI_Wait()
与调用 MPI_Send()
和 [=37= 相同], 分别.
I have a couple of problems: the first one is (rank + 1) % size does
not make sense to me. I expect this to be just rank+1 rahther than
(rank + 1) % size.
为了向您解释该表达式背后的原因,让我们考虑一下您的代码有 4 个进程,等级从 0 到 3。
进程 1、2 和 3 将调用:
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
- 进程 1 需要来自进程 0 的消息;
- 进程 2 需要来自进程 1 的消息;
- 进程 3 需要进程 2 的消息;
然后所有四个进程调用(让我们相应地替换公式 (rank + 1) % size):
MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);
- 进程 0 从进程 (0 + 1) % 4 -> 1 发送消息;
- 进程 1 从进程 (1 + 1) % 4 -> 2 发送消息;
- 进程 2 从进程 (2 + 1) % 4 -> 3 发送消息;
- 进程 3 从进程 (3 + 1) % 4 -> 0 发送消息;
所以 (rank + 1) % size
被用作一个技巧,这样当你达到最后一个排名时,它 returns 回到第一名的排名。
所有这些都是为了构建 recv/send 消息的以下模式 0 -> 1 -> 2 -> 3 -> 0.
您可能已经注意到,MPI_Recv
和 MPI_Send
分别被调用了 3 次和 4 次。即使您没有遇到任何与此相关的问题,通常,不执行相同数量的 MPI_Recv
/MPI_Send
调用也可能会导致死锁。如果不使用 (rank + 1) % size
而只使用 rank + 1
并过滤掉调用 MPI_Isend
的最后进程,则可以避免这种情况,如下所示:
if(rank + 1 < size)
MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
这意味着进程 3 不会向进程 0 发送消息,但这没关系,因为进程 0 无论如何都不希望收到任何消息。
A 运行 示例:
#include <iostream>
#include <mpi.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Request request;
MPI_Status status;
int size, rank, data;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank>0) {
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
MPI_Wait(&request, &status);
std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
<< std::endl;
}
std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;
data=rank;
if(rank + 1 < size){
MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
}
MPI_Wait(&request, &status);
MPI_Finalize();
return 0;
}
输出:
使用 4 个进程可能的输出:
Hello from rank 0 out of 4
Rank 1 has received message with data 0 from rank 0
Hello from rank 1 out of 4
Rank 2 has received message with data 1 from rank 1
Hello from rank 2 out of 4
Rank 3 has received message with data 2 from rank 2
Hello from rank 3 out of 4
我正在使用 this website 练习一个简单的非阻塞“Hello world”程序。
#include <iostream>
#include <mpi.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Request request;
MPI_Status status;
int size, rank, data;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank>0) {
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
<< std::endl;
}
std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;
data=rank;
MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);
MPI_Finalize();
return 0;
}
我有几个问题:第一个是 (rank + 1) % size
对我来说没有意义。我希望这只是 rank+1
而不是 (rank + 1) % size
。但是,当我删除 %size
时,代码不会 运行。我的第二个歧义是这个特定代码的结果:
#PTP job_id=12493
Rank 3 has received message with data 21848 from rank 2
Hello from rank 3 out of 4
Hello from rank 0 out of 4
Rank 2 has received message with data 22065 from rank 1
Hello from rank 2 out of 4
Rank 1 has received message with data 22043 from rank 0
Hello from rank 1 out of 4
我已将数据定义为等于等级,但它似乎随机抛出一些东西。这是为什么?
TL;DR 您代码中的主要问题(很可能)是数据显示随机值的原因是 MPI_Irecv
和 MPI_Isend
的使用没有MPI_Wait
(或MPI_Test
)的调用。
MPI_Irecv and MPI_Isend are nonblocking communication routines, therefore one needs to use the MPI_Wait (or use MPI_Test测试请求是否完成)确保消息完成,send/receive缓冲区中的数据可以再次安全 操纵。
让我们想象一下,您使用 MPI_Isend
发送一个整数数组而不调用 MPI_Wait
;在这种情况下,您不确定何时可以安全地修改(或取消分配)该数组的内存。 MPI_Irecv
也是如此。尽管如此,调用 MPI_Wait
可确保从那一点开始 read/write (或释放内存)缓冲区没有 undefined behavior 或不一致数据的风险。
在MPI_Isend
期间必须读取和发送缓冲区的内容(例如整数数组);同样,在 MPI_Irecv
期间,接收缓冲区的内容必须到达。同时,可以与正在进行的过程重叠一些计算,但是这个计算不能改变(或读取)send/recv 缓冲区的内容。 然后调用 MPI_Wait
以确保从那时起数据 send/recv 可以安全地 read/modified 没有任何问题。
在您的代码中,无论您如何调用:
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
之后不调用 MPI_Wait
。此外,您更改缓冲区的内容 ,即 data=rank
;。如前所述,这可能导致 未定义的行为 。
您可以通过使用 MPI_Recv and MPI_Send 或调用 MPI_Irecv
和 MPI_Isend
然后调用 MPI_Wait
来解决这个问题。从语义上讲,调用 MPI_Isend()
后调用 MPI_Wait()
或调用 MPI_Recv
后调用 MPI_Wait()
与调用 MPI_Send()
和 [=37= 相同], 分别.
I have a couple of problems: the first one is (rank + 1) % size does not make sense to me. I expect this to be just rank+1 rahther than (rank + 1) % size.
为了向您解释该表达式背后的原因,让我们考虑一下您的代码有 4 个进程,等级从 0 到 3。
进程 1、2 和 3 将调用:
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
- 进程 1 需要来自进程 0 的消息;
- 进程 2 需要来自进程 1 的消息;
- 进程 3 需要进程 2 的消息;
然后所有四个进程调用(让我们相应地替换公式 (rank + 1) % size):
MPI_Isend(&data, 1, MPI_INT, (rank + 1) % size, 0, MPI_COMM_WORLD, &request);
- 进程 0 从进程 (0 + 1) % 4 -> 1 发送消息;
- 进程 1 从进程 (1 + 1) % 4 -> 2 发送消息;
- 进程 2 从进程 (2 + 1) % 4 -> 3 发送消息;
- 进程 3 从进程 (3 + 1) % 4 -> 0 发送消息;
所以 (rank + 1) % size
被用作一个技巧,这样当你达到最后一个排名时,它 returns 回到第一名的排名。
所有这些都是为了构建 recv/send 消息的以下模式 0 -> 1 -> 2 -> 3 -> 0.
您可能已经注意到,MPI_Recv
和 MPI_Send
分别被调用了 3 次和 4 次。即使您没有遇到任何与此相关的问题,通常,不执行相同数量的 MPI_Recv
/MPI_Send
调用也可能会导致死锁。如果不使用 (rank + 1) % size
而只使用 rank + 1
并过滤掉调用 MPI_Isend
的最后进程,则可以避免这种情况,如下所示:
if(rank + 1 < size)
MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
这意味着进程 3 不会向进程 0 发送消息,但这没关系,因为进程 0 无论如何都不希望收到任何消息。
A 运行 示例:
#include <iostream>
#include <mpi.h>
#include <unistd.h>
int main(int argc, char* argv[])
{
MPI_Init(&argc, &argv);
MPI_Request request;
MPI_Status status;
int size, rank, data;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
if (rank>0) {
MPI_Irecv(&data, 1, MPI_INT, rank - 1, 0, MPI_COMM_WORLD,&request);
MPI_Wait(&request, &status);
std::cout << "Rank " << rank << " has received message with data " << data<< " from rank " << rank - 1
<< std::endl;
}
std::cout << "Hello from rank " <<rank << " out of " << size<< std::endl;
data=rank;
if(rank + 1 < size){
MPI_Isend(&data, 1, MPI_INT, (rank + 1) 0, MPI_COMM_WORLD, &request);
}
MPI_Wait(&request, &status);
MPI_Finalize();
return 0;
}
输出: 使用 4 个进程可能的输出:
Hello from rank 0 out of 4
Rank 1 has received message with data 0 from rank 0
Hello from rank 1 out of 4
Rank 2 has received message with data 1 from rank 1
Hello from rank 2 out of 4
Rank 3 has received message with data 2 from rank 2
Hello from rank 3 out of 4