当 MPI_Send 不阻塞时
When MPI_Send doesn't block
我使用了一些实现手动 MPI 广播的代码,基本上是一个将整数从根节点单播到所有其他节点的演示。当然,单播到多个节点的效率不如 MPI_Bcast()
但我只是想检查一下它是如何工作的。
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void my_bcast(void* data, int count, MPI::Datatype datatype, int root, MPI::Intracomm communicator) {
int world_size = communicator.Get_size();
int world_rank = communicator.Get_rank();
if (world_rank == root) {
// If we are the root process, send our data to everyone
int i;
for (i = 0; i < world_size; i++) {
if (i != world_rank) {
communicator.Send(data, count, datatype, i, 0);
}
}
} else {
// If we are a receiver process, receive the data from the root
communicator.Recv(data, count, datatype, root, 0);
}
}
int main(int argc, char** argv) {
MPI::Init();
int world_rank = MPI::COMM_WORLD.Get_rank();
int data;
if (world_rank == 0) {
data = 100;
printf("Process 0 broadcasting data %d\n", data);
my_bcast(&data, 1, MPI::INT, 0, MPI::COMM_WORLD);
} else {
my_bcast(&data, 1, MPI::INT, 0, MPI::COMM_WORLD);
printf("Process %d received data %d from root process\n", world_rank, data);
}
MPI::Finalize();
}
我注意到,如果我删除根不发送给自己的支票,
if (i != world_rank) {
...
}
该程序仍然有效并且不会阻塞,而 MPI_Send()
的默认行为应该是阻塞的,即等待另一端接收到数据。但是 MPI_Recv()
永远不会被根调用。有人可以解释为什么会这样吗?
我 运行 使用以下命令从 root 获取代码(集群在 Amazon EC2 上设置并使用 NFS 作为节点之间的共享存储,所有机器都安装了 Open MPI 1.10.2)
mpirun -mca btl ^openib -mca plm_rsh_no_tree_spawn 1 /EC2_NFS/my_bcast
C文件用
编译
mpic++ my_bcast.c
和mpic++
版本是5.4.0。
您将 阻塞 误认为是 同步 行为。阻塞意味着调用不会 return 直到操作完成。一旦提供的缓冲区可以被程序重新使用,标准发送操作 (MPI_Send
) 就会完成。这意味着消息要么完全传输到接收方,要么由 MPI 库内部存储以供以后传送(缓冲发送)。缓冲行为是特定于实现的,但大多数库将缓冲单个整数大小的消息。通过使用 MPI_Ssend
(或 C++ 等效项)强制同步模式让您的程序挂起。
请注意,C++ MPI 绑定不再是标准的一部分,不应在新软件开发中使用。请改用 C 绑定 MPI_Blabla
。
我使用了一些实现手动 MPI 广播的代码,基本上是一个将整数从根节点单播到所有其他节点的演示。当然,单播到多个节点的效率不如 MPI_Bcast()
但我只是想检查一下它是如何工作的。
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
void my_bcast(void* data, int count, MPI::Datatype datatype, int root, MPI::Intracomm communicator) {
int world_size = communicator.Get_size();
int world_rank = communicator.Get_rank();
if (world_rank == root) {
// If we are the root process, send our data to everyone
int i;
for (i = 0; i < world_size; i++) {
if (i != world_rank) {
communicator.Send(data, count, datatype, i, 0);
}
}
} else {
// If we are a receiver process, receive the data from the root
communicator.Recv(data, count, datatype, root, 0);
}
}
int main(int argc, char** argv) {
MPI::Init();
int world_rank = MPI::COMM_WORLD.Get_rank();
int data;
if (world_rank == 0) {
data = 100;
printf("Process 0 broadcasting data %d\n", data);
my_bcast(&data, 1, MPI::INT, 0, MPI::COMM_WORLD);
} else {
my_bcast(&data, 1, MPI::INT, 0, MPI::COMM_WORLD);
printf("Process %d received data %d from root process\n", world_rank, data);
}
MPI::Finalize();
}
我注意到,如果我删除根不发送给自己的支票,
if (i != world_rank) {
...
}
该程序仍然有效并且不会阻塞,而 MPI_Send()
的默认行为应该是阻塞的,即等待另一端接收到数据。但是 MPI_Recv()
永远不会被根调用。有人可以解释为什么会这样吗?
我 运行 使用以下命令从 root 获取代码(集群在 Amazon EC2 上设置并使用 NFS 作为节点之间的共享存储,所有机器都安装了 Open MPI 1.10.2)
mpirun -mca btl ^openib -mca plm_rsh_no_tree_spawn 1 /EC2_NFS/my_bcast
C文件用
编译mpic++ my_bcast.c
和mpic++
版本是5.4.0。
您将 阻塞 误认为是 同步 行为。阻塞意味着调用不会 return 直到操作完成。一旦提供的缓冲区可以被程序重新使用,标准发送操作 (MPI_Send
) 就会完成。这意味着消息要么完全传输到接收方,要么由 MPI 库内部存储以供以后传送(缓冲发送)。缓冲行为是特定于实现的,但大多数库将缓冲单个整数大小的消息。通过使用 MPI_Ssend
(或 C++ 等效项)强制同步模式让您的程序挂起。
请注意,C++ MPI 绑定不再是标准的一部分,不应在新软件开发中使用。请改用 C 绑定 MPI_Blabla
。