Charles ist genau richtig; die Interkommunikatoren erlauben es Ihnen, zwischen Kommunikatoren zu sprechen (oder, um "normale" Kommunikatoren in diesem Zusammenhang zu unterscheiden, "Intra-Kommunikatoren", was mich nicht als eine Verbesserung empfindet).
Ich habe immer die Verwendung dieser Interkommunikatoren ein wenig verwirrend für die Neulinge gefunden. Nicht die Grundideen, die einen Sinn ergeben, sondern die Mechanik, die (etwa) MPI_Reduce
mit einer von diesen verwendet. Die Gruppe von Aufgaben, die die Reduktion durchführen, spezifiziert den Root-Rang auf dem Fernkommunikator, soweit so gut; aber innerhalb der Remote-Rank-Communicator, jeder nicht der Stamm angibt, MPI_PROC_NULL
als root, während die tatsächliche Wurzel MPI_ROOT
angibt. Die Dinge, die man für Rückwärtskompatibilität tut, hey?
#include <mpi.h>
#include <stdio.h>
int main(int argc, char **argv)
{
int commnum = 0; /* which of the 3 comms I belong to */
MPI_Comm mycomm; /* Communicator I belong to */
MPI_Comm intercomm; /* inter-communicator */
int cw_rank, cw_size; /* size, rank in MPI_COMM_WORLD */
int rank; /* rank in local communicator */
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &cw_rank);
MPI_Comm_size(MPI_COMM_WORLD, &cw_size);
if (cw_rank == cw_size-1) /* last task is IO task */
commnum = 2;
else {
if (cw_rank < (cw_size-1)/2)
commnum = 0;
else
commnum = 1;
}
printf("Rank %d in comm %d\n", cw_rank, commnum);
/* create the local communicator, mycomm */
MPI_Comm_split(MPI_COMM_WORLD, commnum, cw_rank, &mycomm);
const int lldr_tag = 1;
const int intercomm_tag = 2;
if (commnum == 0) {
/* comm 0 needs to communicate with comm 2. */
/* create an intercommunicator: */
/* rank 0 in our new communicator will be the "local leader"
* of this commuicator for the purpose of the intercommuniator */
int local_leader = 0;
/* Now, since we're not part of the other communicator (and vice
* versa) we have to refer to the "remote leader" in terms of its
* rank in COMM_WORLD. For us, that's easy; the remote leader
* in the IO comm is defined to be cw_size-1, because that's the
* only task in that comm. But for them, it's harder. So we'll
* send that task the id of our local leader. */
/* find out which rank in COMM_WORLD is the local leader */
MPI_Comm_rank(mycomm, &rank);
if (rank == 0)
MPI_Send(&cw_rank, 1, MPI_INT, cw_size-1, 1, MPI_COMM_WORLD);
/* now create the inter-communicator */
MPI_Intercomm_create(mycomm, local_leader,
MPI_COMM_WORLD, cw_size-1,
intercomm_tag, &intercomm);
}
else if (commnum == 2)
{
/* there's only one task in this comm */
int local_leader = 0;
int rmt_ldr;
MPI_Status s;
MPI_Recv(&rmt_ldr, 1, MPI_INT, MPI_ANY_SOURCE, lldr_tag, MPI_COMM_WORLD, &s);
MPI_Intercomm_create(mycomm, local_leader,
MPI_COMM_WORLD, rmt_ldr,
intercomm_tag, &intercomm);
}
/* now let's play with our communicators and make sure they work */
if (commnum == 0) {
int max_of_ranks = 0;
/* try it internally; */
MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_MAX, 0, mycomm);
if (rank == 0) {
printf("Within comm 0: maximum of ranks is %d\n", max_of_ranks);
printf("Within comm 0: sum of ranks should be %d\n", max_of_ranks*(max_of_ranks+1)/2);
}
/* now try summing it to the other comm */
/* the "root" parameter here is the root in the remote group */
MPI_Reduce(&rank, &max_of_ranks, 1, MPI_INT, MPI_SUM, 0, intercomm);
}
if (commnum == 2) {
int sum_of_ranks = -999;
int rootproc;
/* get reduction data from other comm */
if (rank == 0) /* am I the root of this reduce? */
rootproc = MPI_ROOT;
else
rootproc = MPI_PROC_NULL;
MPI_Reduce(&rank, &sum_of_ranks, 1, MPI_INT, MPI_SUM, rootproc, intercomm);
if (rank == 0)
printf("From comm 2: sum of ranks is %d\n", sum_of_ranks);
}
if (commnum == 0 || commnum == 2);
MPI_Comm_free(&intercomm);
MPI_Finalize();
}
Danke. Das Detail hier wird geschätzt. Ich denke, es wird eine Weile dauern, bis ich all das verdaue ... – mgilson