如何在不使用 MPI_Send 和 MPI_Recv 例程的情况下仅将元素广播到某些等级
How to Broadcast elements to only certain ranks without using the MPI_Send and MPI_Recv routines
只是一个一般性问题:
我想问一下是否有在不使用 MPI_Send
和 MPI_Recv
例程的情况下仅将元素广播到 MPI 中的某些等级。
I wanted to ask if there is anyway to broadcast elements to only
certain ranks in MPI without using the MPI_Send MPI_Recv.
让我们先看看 MPI_Bcast 例程的描述。
Broadcasts a message from the process with rank "root" to all other
processes of the communicator
MPI_Bcast
广播例程是集体交流。 Hence:
Collective communication is a method of communication which involves
participation of all processes in a communicator.
请注意粗体文本 ,即 “通信器中的所有进程”。因此,一种方法(实现您想要的)是创建一个由将参与广播例程的进程组成的子集。这个子集可以通过创建一个新的 MPI communicator. To create that communicator one can use the MPI function MPI_Comm_split. About that routine from source 来实现:
As the name implies, MPI_Comm_split
creates new communicators by
“splitting” a communicator into a group of sub-communicators based on
the input values color and key. It’s important to note here that the
original communicator doesn’t go away, but a new communicator is
created on each process.
The first argument, comm, is the communicator
that will be used as the basis for the new communicators. This could
be MPI_COMM_WORLD, but it could be any other communicator as well.
The second argument, color, determines to which new communicator each
processes will belong. All processes which pass in the same value for
color are assigned to the same communicator. If the color is
MPI_UNDEFINED, that process won’t be included in any of the new
communicators. The third argument, key, determines the ordering (rank)
within each new communicator. The process which passes in the smallest
value for key will be rank 0, the next smallest will be rank 1, and so
on. If there is a tie, the process that had the lower rank in the
original communicator will be first. The final argument, newcomm is
how MPI returns the new communicator back to the user.
假设我们只想让排名偶数的进程参与 MPI_Bcast
;我们首先创建通信器:
MPI_Comm new_comm;
int color = (world_rank % 2 == 0) ? 1 : MPI_UNDEFINED;
MPI_Comm_split(MPI_COMM_WORLD, color, world_rank, &new_comm);
并最终为新的通信器调用 MPI_Bcast
:
if(world_rank % 2 == 0){
....
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, new_comm);
...
}
最后我们将释放通信器使用的内存:
MPI_Comm_free(&new_comm);
一个运行代码示例:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc,char *argv[]){
MPI_Init(NULL,NULL); // Initialize the MPI environment
int world_rank;
int world_size;
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
int bcast_value = world_rank;
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = %d, bcast_value = %d \n", world_rank, bcast_value);
MPI_Comm new_comm;
int color = (world_rank % 2 == 0) ? 1 : MPI_UNDEFINED;
MPI_Comm_split(MPI_COMM_WORLD, color, world_rank, &new_comm);
if(world_rank % 2 == 0){
int new_comm_rank, new_comm_size;
MPI_Comm_rank(new_comm, &new_comm_rank);
MPI_Comm_size(new_comm, &new_comm_size);
bcast_value = 1000;
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, new_comm);
printf("MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = %d, new_comm = %d, bcast_value = %d \n", world_rank, new_comm_rank, bcast_value);
MPI_Comm_free(&new_comm);
}
MPI_Finalize();
return 0;
}
此代码示例展示了两个 MPI_Bcast
调用,一个包含 MPI_COMM_WORLD
的所有进程(即 MPI_Bcast 1
)和另一个只有这些进程的一个子集(即 MPI_Bcast 2
)。
输出(8 个进程):
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 0, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 4, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 5, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 6, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 7, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 1, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 2, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 3, bcast_value = 0
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 0, new_comm = 0, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 4, new_comm = 2, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 2, new_comm = 1, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 6, new_comm = 3, bcast_value = 1000
只是一个一般性问题:
我想问一下是否有在不使用 MPI_Send
和 MPI_Recv
例程的情况下仅将元素广播到 MPI 中的某些等级。
I wanted to ask if there is anyway to broadcast elements to only certain ranks in MPI without using the MPI_Send MPI_Recv.
让我们先看看 MPI_Bcast 例程的描述。
Broadcasts a message from the process with rank "root" to all other processes of the communicator
MPI_Bcast
广播例程是集体交流。 Hence:
Collective communication is a method of communication which involves participation of all processes in a communicator.
请注意粗体文本 ,即 “通信器中的所有进程”。因此,一种方法(实现您想要的)是创建一个由将参与广播例程的进程组成的子集。这个子集可以通过创建一个新的 MPI communicator. To create that communicator one can use the MPI function MPI_Comm_split. About that routine from source 来实现:
As the name implies,
MPI_Comm_split
creates new communicators by “splitting” a communicator into a group of sub-communicators based on the input values color and key. It’s important to note here that the original communicator doesn’t go away, but a new communicator is created on each process.
The first argument, comm, is the communicator that will be used as the basis for the new communicators. This could be MPI_COMM_WORLD, but it could be any other communicator as well.
The second argument, color, determines to which new communicator each processes will belong. All processes which pass in the same value for color are assigned to the same communicator. If the color is MPI_UNDEFINED, that process won’t be included in any of the new communicators. The third argument, key, determines the ordering (rank) within each new communicator. The process which passes in the smallest value for key will be rank 0, the next smallest will be rank 1, and so on. If there is a tie, the process that had the lower rank in the original communicator will be first. The final argument, newcomm is how MPI returns the new communicator back to the user.
假设我们只想让排名偶数的进程参与 MPI_Bcast
;我们首先创建通信器:
MPI_Comm new_comm;
int color = (world_rank % 2 == 0) ? 1 : MPI_UNDEFINED;
MPI_Comm_split(MPI_COMM_WORLD, color, world_rank, &new_comm);
并最终为新的通信器调用 MPI_Bcast
:
if(world_rank % 2 == 0){
....
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, new_comm);
...
}
最后我们将释放通信器使用的内存:
MPI_Comm_free(&new_comm);
一个运行代码示例:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <mpi.h>
int main(int argc,char *argv[]){
MPI_Init(NULL,NULL); // Initialize the MPI environment
int world_rank;
int world_size;
MPI_Comm_rank(MPI_COMM_WORLD,&world_rank);
MPI_Comm_size(MPI_COMM_WORLD,&world_size);
int bcast_value = world_rank;
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = %d, bcast_value = %d \n", world_rank, bcast_value);
MPI_Comm new_comm;
int color = (world_rank % 2 == 0) ? 1 : MPI_UNDEFINED;
MPI_Comm_split(MPI_COMM_WORLD, color, world_rank, &new_comm);
if(world_rank % 2 == 0){
int new_comm_rank, new_comm_size;
MPI_Comm_rank(new_comm, &new_comm_rank);
MPI_Comm_size(new_comm, &new_comm_size);
bcast_value = 1000;
MPI_Bcast(&bcast_value, 1, MPI_INT, 0, new_comm);
printf("MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = %d, new_comm = %d, bcast_value = %d \n", world_rank, new_comm_rank, bcast_value);
MPI_Comm_free(&new_comm);
}
MPI_Finalize();
return 0;
}
此代码示例展示了两个 MPI_Bcast
调用,一个包含 MPI_COMM_WORLD
的所有进程(即 MPI_Bcast 1
)和另一个只有这些进程的一个子集(即 MPI_Bcast 2
)。
输出(8 个进程):
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 0, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 4, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 5, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 6, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 7, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 1, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 2, bcast_value = 0
MPI_Bcast 1 : MPI_COMM_WORLD ProcessID = 3, bcast_value = 0
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 0, new_comm = 0, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 4, new_comm = 2, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 2, new_comm = 1, bcast_value = 1000
MPI_Bcast 2 : MPI_COMM_WORLD ProcessID = 6, new_comm = 3, bcast_value = 1000