2012-12-13 23 views
25

Finora, la mia applicazione sta leggendo in un file txt con un elenco di numeri interi. Questi numeri interi devono essere memorizzati in un array dal processo master, cioè processore con grado 0. Funziona correttamente.Come vengono utilizzati MPI_Scatter e MPI_Gather da C?

Ora, quando eseguo il programma, ho un'istruzione if che controlla se si tratta del processo principale e, in caso affermativo, sto eseguendo il comando MPI_Scatter.

Da quello che ho capito, suddividerà l'array con i numeri e lo passerà ai processi slave, cioè tutti con rank> 0. Tuttavia, non sono sicuro di come gestire lo MPI_Scatter. In che modo lo slave processa "subscribe" per ottenere il sub-array? Come posso dire ai processi non-master di fare qualcosa con il sotto-array?

Qualcuno può fornire un semplice esempio per mostrarmi come il processo master invia elementi dall'array e poi fare in modo che gli slave aggiungano la somma e la restituiscano al master, che somma tutte le somme e le stampa?

Il mio codice finora:

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

risposta

56

Questo è un equivoco comune di come le operazioni di lavoro in MPI con nuove persone ad essa; in particolare con le operazioni collettive, in cui le persone cercano di iniziare a utilizzare la trasmissione (MPI_Bcast) solo dal grado 0, aspettandosi che la chiamata "spinga" in qualche modo i dati agli altri processori. Ma non è così che funzionano le routine MPI; la maggior parte delle comunicazioni MPI richiede sia al mittente che al destinatario di effettuare chiamate MPI.

In particolare, MPI_Scatter() e MPI_Gather() (e MPI_Bcast, e molti altri) sono collettive operazioni; devono essere chiamati da all delle attività nel communicator. Tutti i processori nel communicator effettuano la stessa chiamata e l'operazione viene eseguita. (Ecco perché scatter e gather richiedono entrambi come uno dei parametri il processo "root", da cui provengono tutti i dati). Facendolo in questo modo, l'implementazione MPI ha un sacco di possibilità per ottimizzare i modelli di comunicazione.

Quindi, ecco un semplice esempio (Aggiornato per includere raccogliere):

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

esecuzione dà:

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

Che una risposta eccellente. Ho fatto in modo molto semplice e vedo come funziona ora. Ho fatto l'errore di non pensarci come operazioni collettive. Grazie mille! – DSF

+2

Wow! Mi hai salvato la giornata, Saluti. Grazie – irobo

+0

Più utile della maggior parte della maggior parte delle intrusioni di MPI – WakaChewbacca

Problemi correlati