MPI (Message Passing Interface) para mortales
En general podemos decir que es un protocolo de comunicación entre computadores, creado y usado básicamente en la computación en paralelo, funciona, cómo su nombre lo indica por medio del paso de mensajes, a través de una interfaz especial para ello.
Las implementaciones en MPI consisten en un "conjunto de librerías de rutinas" que pueden ser integradas con lenguajes de programación tales como Ada, C, C++, Fortran, Java, Perl y Python, entre otros. El uso de está permite la sincronización de procesos y exclusión mutua.
Los elementos principales en la comunicación son:
- Proceso emisor (Front End)
- Proceso receptor (Nodos)
- Mensaje de procedimiento
Algunas de sus características son:
- Gestión de procesos
- Gestión de operaciones
- Flexible a multiprocesadores, multicomputadores, redes
- Creación de tipos de datos arbitrariamente :)
A nivel de tipos de datos encontramos:
- MPI_CHAR -- signed char
- MPI_SHORT -- signed short int
- MPI_INT -- signed int
- MPI_LONG -- signed long int
- MPI_UNSIGNED_CHAR -- unsigned char
- MPI_UNSIGNED_SHORT -- unsigned short int
- MPI_UNSIGNED -- unsigned int
- MPI_UNSIGNED_LONG -- unsigned long int
- MPI_FLOAT -- float
- MPI_DOUBLE -- double
- MPI_LONG_DOUBLE -- long double
- MPI_BYTEMPI_PACKED -- byte
Sus primitivas se pueden generalizar en:
- MPI_INIT - iniciar el sistema MPI
- MPI_FINALIZE - terminar el cómputo con MPI
- MPI_COMM_SIZE - determinar el número de procesos
- MPI_COMM_RANK - determinar el identificador del
- propio proceso
- MPI_SEND - mandar un mensaje
- MPI_RECV - recibir un mensaje
Ahora veamos un ejemplo:
Usando código secuencial para la suma de los números de 1 - 1000 tendríamos:
#include
int main(int argc, char **argv)
{ int suma,i;
suma = 0;
for(i=1;i=<1000;i++)
suma = suma + i;
cout << “La suma de 1 a 1000 es: " << suma << endl;
}
Usando código en paralelo para la suma de los números de 1 - 1000 tendríamos:
#include
#include
int main(int argc, char ** argv)
{ int minodo, totalnodos;
int suma,valorinicial,valorfinal,accum;
MPI_Status status;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &totalnodos);
MPI_Comm_rank(MPI_COMM_WORLD, &minodo);
suma = 0;
valorinicial = 1000*minodo/totalnodos+1;
valorfinal = 1000*(minodo+1)/totalnodos;
for(int i=valorinicial;1<=valorfinal;i=i+1
suma = suma + i;
if(minodo!=0)
MPI_Send(&suma,1,MPI_INT,0,1,MPI_COMM_WORLD);
else
for(int j=1; j<= totalnodos; j=j+1 ){
MPI_Recv(&accum,1,MPI_INT,j,1,MPI_COMM_WORLD, &status);
suma = suma + accum;}
if(minodo == 0)
cout << "The suma from 1 to 1000 is: " << suma << endl;MPI_Finalize();}
Es fácil no?
Ahora, explicando un poco el código con MPI debemos destacar básicamente lo siguiente:
- MPI_Status: Es el resultado que obtenemos a la recepción de un mensaje, dicho mensaje contiene datos como el tamaño del mensaje,las etiquetas que contiene (emisor y receptor)
- MPI_Init: Inicia o lanza la aplicación en paralelo
- MPI_Comm_size: Indica el número de procesos que van a participar en la ejecución
- MPI_Comm_rank: Permite asignar los procesos a cada nodo
- MPI_Send: Envío del proceso
- MPI_Recv: Recepción de los datos (resultado del proceso ejecutado)
- MPI_Finalize: Finaliza la aplicación
Gráficamente podríamos verlo de la siguiente forma:
Estado inicial
Conexión con los correspondientes nodos
Envío del proceso
División del proceso en múltiples procesos
Ejecución en paralelo de los correspondientes procesos
Envío de respuestas
Recepción de respuestas
Fin de la comunicación
Para finalizar debemos cualquier proceso no puede paralelizable por ejemplo la
suma de fibonacci, además de que si tenemos procesos "pequeños" el uso de computación en paralelo no es nada recomendable, puesto que gran parte del tiempo se consumirá en el paso de mensajes, lo cual lo haría eficiente... es decir la computación en paralelo está destinada a ser usada para procesos que requieren gran capacidad de procesamiento.
Créditos:
Información tomada de: Presentación "PROCESAMIENTO EN PARALELO USANDO CLUSTER DE COMPUTADORES" por Wilson Castaño, Miguel Mateus y Katherine Cancelado.