Jak są używane MPI Scatter i MPI Gather z C?
Jak na razie moja aplikacja czyta w pliku txt z listą liczb całkowitych. Te liczby całkowite muszą być przechowywane w tablicy przez proces główny, tzn. procesor o randze 0. To działa dobrze.
Teraz, kiedy uruchamiam program, mam polecenie if sprawdzające, czy jest to proces główny, a jeśli tak, wykonuję polecenie MPI_Scatter
.
Z tego, co rozumiem, to podzieli tablicę z liczbami i przekaże ją procesom slave, tzn. wszystkim o rank > 0 . Jednak nie jestem pewien, jak poradzić sobie z MPI_Scatter
. W jaki sposób proces slave "subskrybuje", aby uzyskać tablicę podrzędną? Jak mogę powiedzieć procesom nie-nadrzędnym, żeby coś zrobili z podrzędną macierzą?
Czy ktoś może podać prosty przykład, aby pokazać mi, jak proces master wysyła elementy z tablicy, a następnie niech niewolniki dodają sumę i zwrócą ją do mastera, który doda wszystkie sumy razem i wyświetli je?
Mój kod do tej pory:
#include <stdio.h>
#include <mpi.h>
//A pointer to the file to read in.
FILE *fr;
int main(int argc, char *argv[]) {
int rank,size,n,number_read;
char line[80];
int numbers[30];
int buffer[30];
MPI_Init(&argc, &argv);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &size);
fr = fopen ("int_data.txt","rt"); //We open the file to be read.
if(rank ==0){
printf("my rank = %d\n",rank);
//Reads in the flat file of integers and stores it in the array 'numbers' of type int.
n=0;
while(fgets(line,80,fr) != NULL) {
sscanf(line, "%d", &number_read);
numbers[n] = number_read;
printf("I am processor no. %d --> At element %d we have number: %d\n",rank,n,numbers[n]);
n++;
}
fclose(fr);
MPI_Scatter(&numbers,2,MPI_INT,&buffer,2,MPI_INT,rank,MPI_COMM_WORLD);
}
else {
MPI_Gather ( &buffer, 2, MPI_INT, &numbers, 2, MPI_INT, 0, MPI_COMM_WORLD);
printf("%d",buffer[0]);
}
MPI_Finalize();
return 0;
}
1 answers
Jest to powszechne nieporozumienie w jaki sposób operacje działają w MPI z ludźmi nowicjuszami; szczególnie z operacjami kolektywnymi, gdzie ludzie próbują zacząć używać broadcast (MPI_Bcast
) tylko od rangi 0, oczekując połączenia, aby w jakiś sposób "wypchnąć" dane do innych procesorów. Ale tak naprawdę nie działa procedura MPI; większość komunikacji MPI wymaga zarówno nadawcy, jak i odbiorcy do wykonywania połączeń MPI.
W szczególności, MPI_Scatter()
i MPI_Gather()
(i MPI_Bcast
i wiele innych) są operacje zbiorowe ; muszą być wywoływane przez wszystkie zadania w komunikatorze. Wszystkie procesory w komunikatorze wykonują to samo połączenie i operacja jest wykonywana. (Dlatego zarówno scatter, jak i gather wymagają jako jednego z parametrów procesu "root", do którego trafiają / pochodzą wszystkie dane). Robiąc to w ten sposób, implementacja MPI ma wiele możliwości optymalizacji wzorców komunikacyjnych.
Oto prosty przykład (zaktualizowany do include):
#include <mpi.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
int size, rank;
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &size);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
int *globaldata=NULL;
int localdata;
if (rank == 0) {
globaldata = malloc(size * sizeof(int) );
for (int i=0; i<size; i++)
globaldata[i] = 2*i+1;
printf("Processor %d has data: ", rank);
for (int i=0; i<size; i++)
printf("%d ", globaldata[i]);
printf("\n");
}
MPI_Scatter(globaldata, 1, MPI_INT, &localdata, 1, MPI_INT, 0, MPI_COMM_WORLD);
printf("Processor %d has data %d\n", rank, localdata);
localdata *= 2;
printf("Processor %d doubling the data, now has %d\n", rank, localdata);
MPI_Gather(&localdata, 1, MPI_INT, globaldata, 1, MPI_INT, 0, MPI_COMM_WORLD);
if (rank == 0) {
printf("Processor %d has data: ", rank);
for (int i=0; i<size; i++)
printf("%d ", globaldata[i]);
printf("\n");
}
if (rank == 0)
free(globaldata);
MPI_Finalize();
return 0;
}
Running it gives:
gpc-f103n084-$ mpicc -o scatter-gather scatter-gather.c -std=c99
gpc-f103n084-$ mpirun -np 4 ./scatter-gather
Processor 0 has data: 1 3 5 7
Processor 0 has data 1
Processor 0 doubling the data, now has 2
Processor 3 has data 7
Processor 3 doubling the data, now has 14
Processor 2 has data 5
Processor 2 doubling the data, now has 10
Processor 1 has data 3
Processor 1 doubling the data, now has 6
Processor 0 has data: 2 6 10 14
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-12-13 21:26:52