2012-12-13 6 views
25

Bis jetzt liest meine Anwendung in einer TXT-Datei mit einer Liste von ganzen Zahlen. Diese Ganzzahlen müssen in einem Array durch den Master-Prozess, d. H. Prozessor mit Rang 0, gespeichert werden. Dies funktioniert gut. JetztWie werden MPI_Scatter und MPI_Gather von C verwendet?

, wenn ich das Programm laufen habe ich eine if-Anweisung überprüft, ob es der Master-Prozess ist, und wenn es ist, ich bin die Ausführung des Befehls MPI_Scatter.

Von was ich verstehe, wird dies das Array mit den Zahlen unterteilen und es an die Slave-Prozesse, d. H. Alle mit Rang> 0 übergeben. Ich bin mir jedoch nicht sicher, wie ich mit der MPI_Scatter umgehen soll. Wie "abonniert" der Slave-Prozess, um das Sub-Array zu erhalten? Wie kann ich den Nicht-Master-Prozessen mitteilen, etwas mit dem Sub-Array zu tun?

Kann mir bitte jemand ein einfaches Beispiel geben, um mir zu zeigen, wie der Masterprozess Elemente aus dem Array sendet und dann die Slaves die Summe addiert und an den Master zurückgibt, der alle Summen addiert und ausgibt?

Mein Code so weit:

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

Antwort

56

Dies ist ein weit verbreitetes Missverständnis, wie Operationen mit Menschen, um es neu in MPI arbeiten; insbesondere bei kollektiven Operationen, bei denen Leute versuchen, Broadcast (MPI_Bcast) gerade von Rang 0 zu verwenden, in der Erwartung, dass der Anruf irgendwie die Daten zu den anderen Prozessoren "verschiebt". Aber so funktionieren MPI-Routinen nicht wirklich; Die meiste MPI-Kommunikation erfordert sowohl den Sender als auch den Empfänger, um MPI-Anrufe zu tätigen.

Insbesondere MPI_Scatter() und MPI_Gather() (und MPI_Bcast, und viele andere) sind kollektive Operationen; Sie müssen von alle der Aufgaben im Communicator aufgerufen werden. Alle Prozessoren im Communicator führen denselben Aufruf aus, und die Operation wird ausgeführt. (Das ist der Grund, warum streuen und sammeln beide als einen der Parameter den "root" -Prozess benötigen, wo alle Daten zu/von kommen). Auf diese Weise hat die MPI-Implementierung viel Spielraum, um die Kommunikationsmuster zu optimieren.

Also hier ist ein einfaches Beispiel ( aktualisiert, um sammeln):

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

Läuft es gibt:

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

Was für eine ausgezeichnete Antwort. Habe es sehr geradlinig gemacht und ich sehe wie es jetzt funktioniert. Ich habe den Fehler gemacht, darüber nicht als kollektive Operationen zu denken. Vielen Dank! – DSF

+2

Wow! Du hast meinen Tag gerettet, Prost. Danke – irobo

+0

Hilfreicher als die meisten MPI Intros – WakaChewbacca