Programare distribuită folosind mpi

Aplicația Parallel1 constă în mai multe procese sau sarcini care sunt executate simultan. Biblioteca de suport MPI creează singur numărul de procese specificate. Când programul devine control, toate procesele sunt deja create. Puteți specifica că mai multe sarcini ar trebui să fie difuzate pe același procesor. În acest caz, executarea lor paralelă va fi simulată. Pentru a efectua calculele, procesele sunt grupate împreună. Fiecare proces din grup are un număr unic. De obicei, procesul cu numărul 0 este considerat principalul proces și controlează restul.






Feature MPI este conceptul domeniilor de comunicare (domenii de comunicare). Când începe aplicația, toate procesele sunt plasate într-o zonă de comunicare. În viitor, puteți crea noi domenii bazate pe cele existente. Toate zonele de comunicare au un sistem independent de numerotare a proceselor. Un comunicator este un programator - un descriptor al zonei de comunicare. Cele mai multe funcții ale bibliotecii iau unul dintre parametri ca un comunicator, ceea ce le limitează domeniul de aplicare la zona specificată. Zona de comunicare inițială, care este creată automat la pornire, utilizează comunicatorul MPI_COMM_WORLD.
Prototipurile majorității funcțiilor bibliotecii sunt declarate în fișierul "mpi.h". Există mai multe funcții care ar trebui să fie numite de orice program distribuit (a se vedea Tabelul 1).
Tabel. 1. Funcții de inițializare și deinitializare a bibliotecii MPI

Tabel. 1. Funcții de inițializare și deinitializare a bibliotecii MPI

MPI_Init (int * argc, char *** argv)

Inițializează biblioteca. Recepționează indicatorii ca parametri
la parametrii standard ai principalelor

Finalizarea completă a bibliotecii. Funcția trebuie apelată înainte ca programul să se termine


Biblioteca conține, de asemenea, un set de funcții de informare. În tabel. 2 arată două dintre ele.
Tabel. 2. Funcțiile de informare ale MPI

Tabel. 2. Funcțiile de informare ale MPI

MPI_Comm_size (comanda MPI_Comm, int * size)

Scrie dimensiunea grupului la argumentul de mărime, adică numărul total de procese care rulează în zona de comunicație specificată com

MPI_Comm_rank (comanda MPI_Comm, int * rank)

Parametrul rank plasează numărul procesului care a apelat funcția


Acum putem scrie un program simplu distribuit:

/ * fișierul primul.c * /
#include
/ * prototipuri de funcții MPI * /
#include "mpi.h"
int principal (int argc, char ** argv)
int myrank, dimensiune;
/ * Initializeaza biblioteca * /
MPI_Init (argc, argv);
/ * determina numărul de procese * /
MPI_Comm_size (MPI_COMM_WORLD, dimensiune);
/ * Definiți numărul procesului * /
MPI_Comm_rank (MPI_COMM_WORLD, myrank);
/ * ieșirea informațiilor primite * /
printf ("Mărimea numărului. \ n", myrank, dimensiune);
/ * Închideți biblioteca * /
MPI_Finalizare ();
retur 0;
>

Compilarea și rularea programelor paralele

Pentru a compila programe C care utilizează MPICH, ar trebui să utilizați scriptul mpicc. Începe cu aceiași parametri ca și compilatorul C și adaugă parametrii necesari pentru conectarea bibliotecii:

mpicc -o primul primul.c

Pentru a porni programul, utilizați scriptul mpirun. Trebuie să specificați numărul de procese pe care trebuie să le creați și numele fișierului executabil:







mpirun -np 4 ./first

După pornire, pe ecran veți vedea următoarele:

Numărul 3 al mărimii 4
Numărul 0 dimensiune 4
Numărul 2 al mărimii 4
Numărul 1 de dimensiune 4

Ordinea de execuție a proceselor este incertă. Prin urmare, liniile de pe ecran vor apărea în ordine aleatorie. Pentru a verifica acest lucru, porniți programul de mai multe ori.

Trimiterea și primirea mesajelor

După cum sa menționat deja, una dintre căile de interacțiune a proceselor distribuite este transmiterea mesajelor. MPI (Message Passing Interface) definește un set de funcții prin care sarcinile pot primi și transmite mesaje. Fiecare mesaj are un set de atribute - numărul procesului de trimitere, numărul procesului de primire și identificatorul mesajului. Identificatorul mesajului este un număr întreg cuprins între 0 și 32767.

Cele două funcții simple pentru recepție / transmitere sunt prezentate în Tabelul. 3.
Tabel. 3. Cele mai simple funcții ale recepției / transmisiei MPI

Tabel. 3. Cele mai simple funcții ale recepției / transmisiei MPI

int MPI_Send (void * buf, int count, PI_Datatype datatype, int dest, int msgtag, MPI_Comm comm)

Execută o trimitere blocantă a unui mesaj cu identificatorul msgtag, constând din elemente de numărare de tipul de tip dat, la procesul cu numărul dest. Toate elementele mesajului sunt alocate într-un rând în buffer buf. Valoarea numărului poate fi zero. Tipul elementelor de date transmise trebuie să fie specificat utilizând constante tip predefinite. Îți poți trimite un mesaj.

int MPI_Recv (void * buf, int count, MPI_Datatype datatype, int sursă, int msgtag, MPI_comm
com, starea MPI_Status *)

Primeste un mesaj cu identificatorul msgtag din procesul sursei cu o blocare. Numărul de elemente din mesajul primit nu trebuie să depășească valoarea contorului. Dacă numărul elementelor recepționate este mai mic decât valoarea contorului, atunci se garantează că numai elementele corespunzătoare elementelor mesajului primit se vor schimba în buf.

Aceste funcții efectuează o transmisie-recepție de blocare, i. E. Atunci când sunt utilizate, controlul procesului de apelare este returnat numai după ce datele sunt recepționate sau transmise (sau copiate în buffer-ul temporar).

Tipuri de date în MPI

Funcțiile MPI trebuie să specifice tipul de date care trebuie transmise. Acest lucru se datorează faptului că procesele distribuite de programe pot fi executate simultan pe mașini cu arhitecturi diferite, ordine byte și reprezentare de date. Prin urmare, toate funcțiile de recepție și de transmisie în MPI nu funcționează prin numărul de octeți transmiși, ci prin numărul de celule al căror tip este specificat de parametrul funcției. În MPI se utilizează un tip special - tipul de tip "MPI_Datatype", fiecare dintre variabilele sale descriind un tip pentru MPI. Pentru fiecare tip de date de bază disponibil în limba de programare utilizată, constantele corespunzătoare 2 sunt definite în biblioteca MPI.

De exemplu, în Tabelul. 4 arată constantele definite pentru limba C.
Tabel. 4. Constante MPI și tipuri de date C

Tabel. 4. Constante MPI și tipuri de date C


Cel mai simplu program care efectuează transferul de date între procese poate avea următoarea formă:

/ * Fișierul mpi2.c * /
#include
#include "mpi.h"
int principal (int argc, char ** argv)
în mine;
mesajul char [20];
Statutul MPI_Status;

MPI_Init (argc, argv);
MPI_Comm_rank (MPI_COMM_WORLD, mine);
dacă (eu == 0) / * acesta este procesul principal * /
strcpy (mesaj, "Bună ziua, acolo");
/ * trimite procesul 1 șir de caractere; mesajul are numărul 99 * /
MPI_Send (mesaj, strlen (mesaj) + 1, MPI_CHAR, 1, 99, MPI_COMM_WORLD);
>
altfel / * este un proces auxiliar * /
/ * Așteptăm din procesul 0 al mesajului 99, care conține un șir de caractere * /
MPI_Recv (mesaj, 20, MPI_CHAR, 0, 99, MPI_COMM_WORLD, statut);
printf ("proc. primeste:% s \ n", mesajul meu);
>

MPI_Finalizare ();
retur 0;
>

Programul este conceput pentru numai două procese, deci trebuie să fie rulat după cum urmează:

mpirun -np 2 ./mpi2

Pe ecran se afișează următoarele:

proc 1 a primit: Bună ziua, acolo

Dacă scriptul mpirun specifică opțiunea -l, înainte de fiecare linie de ieșire va fi imprimat numărul procesului care imprimă această linie:

mpirun -l-np 2 ./mpi2
1: proc 1 a primit: Bună, acolo

Am examinat elementele de bază ale programării programelor distribuite folosind biblioteca MPI. În următorul articol, vor fi luate în considerare funcții și exemple mai complexe și mai puternice.

1 Programele paralele care rulează pe diferite mașini sunt numite distribuite pentru a sublinia diferența lor față de programele care rulează pe un sistem multiprocesor (de obicei cu memorie partajată). În articol, termenii paralele și distribuite sunt folosite ca sinonime.







Articole similare

Trimiteți-le prietenilor: