2012-12-13 12 views
25

Do tej pory moja aplikacja czyta w pliku txt listę liczb całkowitych. Te liczby całkowite muszą być przechowywane w tablicy przez proces główny, tj. Procesor z pozycją 0. Działa to dobrze.W jaki sposób MPI_Scatter i MPI_Gather są używane z C?

Teraz po uruchomieniu programu mam instrukcję if sprawdzającą, czy jest to proces główny, a jeśli tak, to wykonuję polecenie MPI_Scatter.

Z tego co rozumiem, podzieli tablicę z liczbami i przekaże ją procesom slave, czyli wszystkim o pozycji> 0. Jednak nie jestem pewien, jak obsługiwać MPI_Scatter. W jaki sposób proces podrzędny "subskrybuj", aby uzyskać tablicę podrzędną? W jaki sposób mogę powiedzieć procesom innym niż wzorcowe, aby coś zrobiły z tablicą podrzędną?

Czy ktoś może podać prosty przykład, aby pokazać mi, w jaki sposób główny proces wysyła elementy z tablicy, a następnie czy niewolnicy dodają sumę i zwracają ją do wzorca, która dodaje wszystkie sumy i wypisuje 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; 
} 

Odpowiedz

56

Jest to powszechne niezrozumienie jak operacje pracować w MPI z ludźmi nowe do niej; szczególnie w przypadku operacji zbiorowych, w których ludzie próbują zacząć używać emisji (MPI_Bcast) tuż przed pozycją 0, oczekując, że połączenie w jakiś sposób "przepchnie" dane do innych procesorów. Ale tak nie jest, jak działają procedury 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) zbiorowe operacji; muszą być wywoływane przez wszystkie zadań w komunikatorze. Wszystkie procesory w komunikatorze wykonują to samo połączenie i operacja jest wykonywana. (Dlatego rozproszenie i zbieranie obydwu wymagają jako jednego z parametrów procesu "root", w którym wszystkie dane trafiają do/pochodzą). Robiąc to w ten sposób, implementacja MPI ma wiele możliwości optymalizacji wzorców komunikacji.

Więc oto prosty przykład (Updated obejmuje zebranie):

#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; 
} 

Bieganie daje:

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 
+2

Co doskonałą odpowiedzią. Zrobiłem to bardzo prosto i widzę, jak to działa teraz. Popełniłem błąd, nie myśląc o tym jako o operacjach zbiorowych. Wielkie dzięki! – DSF

+2

Wow! Uratowałeś mi dzień, Na zdrowie. Dziękujemy – irobo

+0

Bardziej przydatne niż większość wejść MPI – WakaChewbacca

Powiązane problemy