
- •Isbn 978-601-217-247-8
- •Есептеу машиналары
- •§1.1.1 Параллель виртуалды машиналар
- •1 Сурет. Vm/sp, vм/ха, vn/еsа машиналары
- •2 Сурет. Виртуалды машина жүйесі
- •3 Сурет. VMware терезесі
- •4 Сурет. Бір компьютерде бірнеше операциялық жүйе
- •5 Сурет. Вм консолынің мысалы
- •6 Сурет. Виртуалды машиналар жүйесінің архитектурасы
- •§1.1.2 Виртуалды машиналардың түрлері
- •§1.1.3 Виртуаландыру - ақпараттық жүйелерді реттеудің басты жолы
- •§1.2.1 Компьютердің аппараттық құрылымын жетілдіру
- •7 Сурет. Бір операцияны бес тактіде орындайтын тізбекті құрылғының
- •8 Сурет. Бір операцияны әрбірі бес тактіде орындайтын екі бірдей тізбекті
- •10 Сурет. Конвейерлік құрылғы өнімділігінің кіріс деректер
- •11 Сурет. Illiac IV матрицалық жүйесінің жобасы
- •§1.2.2 Компьютерді басқарудың интеллектуалдығын жоғарылату
- •12 Сурет. Ортақ жадылы параллель компьютерлер
- •13 Сурет. Таратылған жадылы параллель компьютерлер
- •14 Сурет. Ортақ шиналы мультипроцессорлық жүйе.
- •15 Сурет. Матрицалық коммутаторлардағы
- •16 Сурет. Омега - желі мультипроцессорлық жүйесі.
- •17 Сурет. Мультикомпьютерлерлік жүйелер байланыс топологияларымен: а – сызықша; б – дөңгелек; в – жұлдызша
- •18 Сурет. Процессорлардың байланыс топологияларының нұсқалары
- •19 Сурет. Сm* есептеу жүйесінің сызбасы
- •20 Сурет. Bbn Butterfly есептеу жүйесінің сызбасы
- •§1.2.3 Функционалды құрылғылар жүйесі
- •§1.3.1 Параллель компьютерлер және жүйелер классификациясы
- •21 Сурет. М. Флин классификациясының sisd және simd кластары
- •22 Сурет. М. Флин классификациясының misd және mimd кластары
- •23 Сурет. Mimd класына р. Хокнидың қосымша
- •§1.3.2 Векторлы-конвейерлік компьютелер
- •24 Сурет. Cray c90 компьютерінің жалпы сүлбесі
- •25 Сурет. Cray c90 компьютері жадысының бөлінуі
- •26 Сурет. Cray c90 компьютерінде векторлық операциялардың орындалуы
- •27 Сурет. Cray c90 компьютерінде векторлық операциялардың ілінісуі
- •§1.3.3 Ортақ жадылы параллель компьютерлер
- •28 Сурет. Hewlett Packard Superdome компьютері
- •29 Сурет. Hewlett Packard Superdome компьютерінің
- •§1.3.4 Таратылған жадылы есептеу жүйелері
- •30 Сурет. Cray t3e компьютерінің коммуникациялық торы
- •31 Сурет. Cray т3d/t3e компьютерлеріндегі барьерлі синхрондау
- •32 Сурет. Есептеу кластерінің жалпы схемасы
- •33 Сурет. Мвс-1000м суперкомпьютерінің құрылымы
- •34 Сурет. Коммуникациялық ортаның латенттілігі және өткізу қабілеті
- •§1.3.5 Метакомпьютинг
- •§2.1.1 Үлкен есептер және үлкен компьютерлер
- •35 Сурет. Сандық эксперименттің этаптары
- •§ 2.1.2 Алгоритм графы және параллель есептеулер
- •§ 2.1.3 Шексіз параллелділік концепциясы
- •§ 2.1.4 Ішкі параллельділік
- •37 Сурет. Матрицаларды көбейту графы
- •38 Сурет. Үшбұрышты жүйелерге арналған графтар
- •39 Сурет. Блокты-екідиагоналды жүйеге арналған Макрограф
- •40 Сурет. Блокты-екідиагоналды жүйеге арналған граф
- •41 Сурет. Жалпыланған пралллель форманың ярустары
- •42 Сурет. Графтағы микро және макропараллельділік
- •§2.2.1 Дәстүрлі тізбекті тілдерді пайдалану.
- •§2.2.2 OpenMp бағдарламалау технологиясы
- •44 Сурет. ОреnМр: бағдарламаның орындалу процесі
- •§2.2.3 Хабарлама жіберу негізіндегі бағдарламалау жүйелері. Mpi бағдарламалау жүйесі
- •Int mpi_Comm_rank(mpi_Comm comm, int *rank)
- •Int mpi_Send(void *buf, int count, mpi_Datatype datatype, int dest, int msgtag, mpi_Comm comm)
- •Integer count, datatype, dest, msgtag, comm, request, ierr
- •Int mpi_Isend(void *buf, int count, mpi_Datatype datatype, int dest, int msgtag, mpi_Comm comm, mpi_Request *request)
- •Int mpi_Irecv(void *buf, int count, mpi_Datatype datatype, int source, int msgtag, mpi_Comm comm, mpi_Request *request)
- •Integer count, datatype, source, msgtag, comm, request, ierr
- •Int main(argc,argv)
- •Int argc;
- •Include 'mpif.H’
- •Integer ierr, rank, size, prev, next, reqs(4), buf(2)
- •Integer stats(mpi_status_size, 4)
- •Int mpi_Waitany( int count, mpi_Request *requests, int *index, mpi_Status *status)
- •Integer count, requests(*), index, status(mpi_status_size), ierr
- •Int mpi_Waitsome( int incount, mpi_Request *requests, int *outcount, int *indexes, mpi_Status *statuses)
- •Integer incount, requests(*), outcount, indexes(*), ierr,
- •Int mpi_Test(mpi_Request *request, int *flag, mpi_Status *status)
- •Integer request, ierr, status(mpi_status_size)
- •Int mpi_Testall( int count, mpi_Request *requests, int *flag, mpi_Status *statuses)
- •Integer count, requests(*), statuses(mpi_status_size,*), ierr
- •Int mpi_Testany(int count, mpi_Request *requests, int *index, int *flag, mpi_Status *status)
- •Integer count, requests(*), index, status(mpi_status_size), ierr
- •Int mpi_Testsome( int incount, mpi_Request *requests, int *outcount, int *indexes, mpi_Status *statuses)
- •Integer incount, requests(*), outcount, indexes(*), ierr,
- •Int mpi_Iprobe( int source, int msgtag, mpi_Comm comm, int *flag, mpi_Status *status)
- •Include 'mpif.H’
- •Integer ierr, rank, size, n, nl, I, j
- •Integer irr, status(mpi_status_size), req(maxproc*2)
- •If(ir .Ne. Rank)
- •Int mpi_Send_init( void *buf, int count, mpi_Datatype datatype, int dest, int msgtag, mpi_Comm comm, mpi_Request *request)
- •Integer count, datatype, dest, msgtag, comm, request, ierr
- •Int mpi_Recv_init( void *buf, int count, mpi_Datatype datatype, int source, int msgtag, mpi_Comm comm, mpi_Request *request)
- •Integer count, datatype, source, msgtag, comm, request, ierr
- •Integer сомм, ierr
- •Include 'mpif.H’
- •Integer ibuf(maxproc)
- •Integer req(2*maxproc), statuses(mpi_status_size, maxproc)
- •Integer count, datatype, root, comm, ierr
- •Integer scount, stype, rcount, rtype, root, comm, ierr
- •Integer scount, stype, rcounts(*), displs(*), rtype, root, comm, ierr
- •Integer scount, stype, rcount, rtype, root, comm, ierr
- •Int mpi_Bcast(void *buf, int count, mpi_Datatype datatype, int source, mpi_Comm comm)
- •Int mpi_Gather( void *sbuf, int scount, mpi_Datatype stype, void *rbuf, int rcount, mpi_Datatype rtype, int dest, mpi_Comm comm)
- •Int mpi_Scatter(void *sbuf, int scount, mpi_Datatype stype, void *rbuf, int rcount, mpi_Datatype rtype, int source, mpi_Comm comm)
- •Int main(argc,argv)
- •Int argc;
- •Int numtasks, rank, sendcount, recvcount, source;
- •Int mpi_Barrier (mpi_Comm comm)
- •§ 2.2.4 Бағдарламалаудың басқа тілдері және жүйелері.
- •Параллель есептеуде қолданылатын қысқаша қазақша-орысша терминологиялық сөздік
- •Параллель есептеуде қолданылатын қысқаша орысша-қазақша терминологиялық сөздік
- •Және орта айнымалылары
- •Mpi функциялары
Int mpi_Comm_rank(mpi_Comm comm, int *rank)
comm - коммуникатор идентификаторы;
out rank - comm коммуникаторындағы процесс нөмірі.
comm коммуникаторындағы процесс нөмірін анықтау. Егер сол comm коммуникаторы үшін MPI_comm_size функциясы size мәнін қайтарса, онда rank айнымалысы арқылы MPI_Comm_rank функциясымен қайтарылған мән 0-ден бастап size – 1-ге дейінгі диапазонда жатады.
double MPI_Wtime(void)
Бұл функция қандай да бір бекітілген моменттен бергі өткен астрономиялық уақытты қайтарады (нақты сан, сек). Егер бағдарламаның қандай да бір жекелеген участогын осы функцияның шақыруларымен қоршасақ, онда қайтарылатын мәндердің айырмасы осы участоктың жұмыс істеген уақытын көрсетеді. Сонымен қатар, процесс орындалуы кезінде санақ нүктесі ретінде пайдаланылған уақыт мезетінің өзгертілмейтініне кепілдік беріледі және де берілген функция өзінің жұмысы нәтижесін параметрлер арқылы емес айқын түрде қайтаратынын байқауға болады.
Жоғарыда сипатталған функциялар пайдаланылған қарапайым бағдарламаны келесі түрде беруге болады:
main(int argc, char **argv)
{
int me, size;
...
MPI_Init(&argc, &argv); MPI_Comm_rank(MPI_COMM_WORLD, &me); MPI_Comm_size(MPI_COMM_WORLD, &size); printf("Process %d size %d \n", me, size);
...
MPI_Finalize();
...
}
MPI_Init функциясы шақырылған кезде қанша процесс туындаған болса, соншама рет printf функциясына сәйкес келетін «жол» шығарылатын болады. Жолдардың пайда болу реті алдын-ала анықталмаған және ол кезкелген болуы мүмкін. Мұнда түрлі жолдардың мазмұндары бір-бірімен араласып кетпеуіне ғана кепілдік беріледі.
Жеке процестер арасында хабарламаны қабылдау/жіберу
MPI бағдарламалау жүйесінің хабарламаны жіберу функциялары екі топқа бөлінеді. Бірінші топқа бағдарламаның екі процесінің арақатынасы үшін арналған функциялар кіреді. Бұндай операциялар дербес (индивидуальный) немесе "нүкте-нүкте" түріндегі операциялар деп аталады. Екінші топқа кіретін функциялар, қандай да бір коммуникатордың барлық процестері операцияға қатыстырылуы керек деп жорамалдайды. Бұндай операциялар ұжымдық деп аталады.
Хабарламалар алмасу функцияларының сипаттамасын "нүкте - нүкте" түріндегі операцияларды талдаудан бастаймыз. Бұл топтың барлық функциялары, өз кезегінде, тағы екі класқа бөлінеді: бұғатталуы бар функциялар және бұғатталуы жоқ функциялар.
Бұғатталуы бар хабарламаларды қабылдау/жіберу келесі түрдегі конструкциялармен беріледі.
Int mpi_Send(void *buf, int count, mpi_Datatype datatype, int dest, int msgtag, mpi_Comm comm)
buf – жіберілетін хабарламасы бар буфердің басталу адресі;
count - хабарламадағы жіберілетін элементтер саны,
datatype - жіберілетін элементтер типтері;
dest -процесс-қабылдаушының нөмірі;
msgtag - хабарлама идентификаторы;
comm - коммуникатор идентификаторы.
Нөмірі dest болатын процеске, типтері datatype және count элементтерден тұратын, идентификаторы msgtag хабарламасының бұғаттайтын посылкасы. Жіберілетін хабарламаның барлық элементтері buf буферінде қатар орналасқан. Хабарламадағы жіберілетін элементтер саны, яғни count мәні нөлге тең болуы мүмкін. Хабарламаны өзіне де жіберуге рұқсат етіледі. Жіберілетін элементтер типі datatype алдын ала анықталған тұрақтылар типтері көмегімен көрсетілуі керек, мысалы, MPI_INT, MPI_LONG, MPI_SHORT, MPI_LONG_DOUBLE, MPI_CHAR, MPI_UNSIGNED_CHAR, MPI_FLOAT немесе енгізілген туынды типтермен. Fortran және С тілдерінің әрбір деректер типі үшін өзінің тұрақтысы бар. Алдын ала анықталған типтер аттарының толық тізімін mpi.h файлынан табуға болады.
Бұғатталу, бағыныңқы бағдарламадан қайтарылған барлық параметрлерді қайталап пайдаланудың дұрыстығына кепілдік береді. Бұл дегеніміз, жіберілетін хабарламаны бүлдірем деп қорықпай, берілген функциядан қайтарылғаннан кейін кезкелген функция шақыруына қатысатын айнымалыларды пайдалануға болады деген сөз. Бұл кепілдікті іске асырудың тәсілін таңдау: аралық буферге көшіру немесе dest процесіне тікелей жіберу, MPI құрастырушыларына қалдырылады.
Арнайы айта кету керек, MPI_Send функциясынан қайтарылу, хабарлама dest процесімен қабылдап алынғанын болмаса хабарлама MPI_Send жүктеген процесс орындалып жатқан процессорлық элементті тастап шыққанын білдірмейді. Мұнда тек берілген функция шақыруында пайдаланылған айнымалыларды ғана қауіпсіз өзгертуге болатынына кепілдік беріледі.
Осындай анықталмағандық, әрине пайдаланушыларды қанағаттандыра қоймайды. Сондықтан, хабарламаны жіберу мүмкіндіктерін кеңейту үшін, қосымша үш функция енгізілген және олардың өз ерекшеліктері бар.
MPI_Bsend - буферленуімен хабарламаны жіберу. Егер жіберілген хабарлама процесс-қабылдаушымен әлі инициалданбаған болса, онда хабарлама буферге жазылады және функциядан жылдам қайтарылып алынады. Берілген функцияның орындалуы оған сәйкес хабарлама қабылдаушы функция шақыруына ешқандай тәуелсіз емес. Солай бола тұра, егер буферге орын жеткіліксіз болса, онда функция қателік кодын қайтаруы (беруі) мүмкін.
MPI_ssend - синхрондалуымен хабарламаны жіберу. Жіберілген хабарлама процесс-қабылдаушымен инициалданған жағдайда ғана берілген функциядан шығу орындалады. Сонымен, синхрондалуымен хабарламаны жіберудің аяқталуы буферді қайта пайдалану мүмкіндігі туралы ғана емес, сонымен қатар бағдарламада процесс-қабылдаушының хабарламаны қабылдау нүктесіне жеткендігнің кепілдігі туралы да айтады. Егер хабарламаны қабылдау бұғатталумен де орындалатын болса, онда MPI_ssend функциясы бұғаттау шақыруларының семантикасын сақтайды.
MPI_Rsend – дайындығымен хабарламаны жіберу. Берілген функцияны сол жағдайда ғана пайдалануға болады, егер процесс-қабылдаушы жіберілген хабарламаны қабылдауды инициалдап қойған болса. Кері жағдайда функцияны шақыру қателік болып есептеледі және оның орындалу нәтижесі анықталмаған. MPI_Rsend процедурасын шақыру алдында хабарламаны қабылдауды инициалдау кепілдігін, процестерді айқын және айқын емес синхрондау жүргізетін операциялар көмегімен беруге болады (мысалы, MPI_BARRIER, немесе MPI_SSEND). Жалпы алғанда, көп жағдайда MPI_Rsend функциясы, жіберуді ұйымдастырудың қосымша шығындарын азайта отырып, жіберуші және қабылдаушы арасындағы арақатынас протоколын қысқартады.
Пайдаланушы жіберілетін процесте, MPI_ВSEND процедурасын шақыру кезінде хабарламаны буферлеу үшін пайдаланылатын арнайы массив тағайындауы керек.
MPI_BUFFER_ATTACH(BUF, SIZE, IERR) <type> BUF(*)
INTEGER SIZE, IERR
Буферлеуімен хабарламаны жіберу кезінде пайдалану үшін өлшемі SIZE болатын BUF массивін тағайындау (Фортран). Әрбір процесте осындай тек бір буфер болуы мүмкін. Жалпы, бағдарламада бұл тағайындалған массивті басқа мақсаттарға пайдалануға болмайды. Буферлеу үшін бөлінген массив өлшемі, хабарламаның жалпы өлшемінен кемінде mpi_bsend_overhead тұрақтысымен анықталған шамаға артық болу керек.
MPI_BUFFER_DETACH(BUF, SIZE, IERR) <type> BUF(*)
INTEGER SIZE, IERR
Басқа мақсаттарға пайдалану үшін бөлінген буферлік массивті босату. Процедура BUF және SIZE аргументтерімен босатылатын массивтің адресін және өлшемін қайтарады. Берілген буферден барлық хабарламалар кетіп болғанға дейін, процедураны шақырған процесс бұғатталады.
Негізінде жіберілетін хабарламаларды буферлеу үшін MPI–да жадының біршама көлімі бөлінеді. Бірақ, нақты іске асырулардың ерекшеліктеріне сенім артпай, бағдарламада барлық жіберілетін буферлеуімен хабарламалар үшін айқын түрде жеткілікті буфер бөлу ұсынылады.
Келесі мысалда буферленуімен хабарлама жіберуді пайдалану көрсетілген. Буферлеу үшін массив buf бөлінеді, жіберілу аяқталғаннан кейін ол босатылады. Қажетті буфер өлшемі хабарлама өлшемі (бір бүтін сан – 4 байт) қосу МРI_BSEND_OVERHEAD тұрақтысының мәнімен анықталады (Фортран).
program example1
include ‘mpif.h’
integer BUFSIZE
parameter (BUFSIZE = 4 + MPI_BSEND_OVERHEAD)
byte buf(BUFSIZE)
integer rank, ierr, ibufsize, rbuf
integer status(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
if(rank .eq. 0) then
call MPI_BUFFER_ATTACH(buf, BUFSIZE, ierr)
call MPI_BSEND(rank, 1, MPI_INTEGER, 1, 5, & MPI_COMM_WORLD, ierr)
call MPI_BUFFER_DETACH(buf, ibufsize, ierr)
end if
if(rank .eq. 1) then
call MPI_RECV(rbuf, 1, MPI_INTEGER, 0, 5, & MPI_COMM_WORLD, status, ierr)
print *, 'Process 1 received', rbuf, ‘from process', & status(MPI_SOURCE)
end if
call MPI_FINALIZE(ierr) end
MPI_RECV(BUF, COUNT, DATATYPE, SOURCE, MSGTAG, COMM, STATUS, IERR)
<type> BUF(*)
INTEGER COUNT, DATATYPE, SOURCE, MSGTAG, COMM, IERR,
STATUS(MPI_STATUS_SIZE)
Идентификаторы MSGTAG типі DATATYPE болатын, саны COUNT-тан аспайтын хабарлама элементтерін BUF буферіне бұғаттау тәсілі. Тәсіл нөмірі SOURCE (COMM коммуникаторындағы) процестен келген хабарлама STATUS атрибуттары массивін толтыра отырып орындалады. Егер нақты қабылданған элементтер саны COUNT мәнінен кіші болса, онда BUF буферінде тек қабылданған хабарлама элементтеріне сәйкес келетін элементтер ғана өзгеретініне кепілдік беріледі. Егер қабылданған элементтер саны COUNT мәнінен үлкен болса, онда толып кету (переполнение) қателігі туындайды. Оны болдырмау үшін алғашында mpi_probe (mpi_iprobe) процедурасы көмегімен келетін хабарлама құрылымын анықтап алуға болады. Егер қабылданған хабарламадағы элементтердің дәл санын білу керек болса, онда mpi_get_count процедурасын пайдалануға болады. Бұғатталу хабарламаның барлық элементтері mpi_recv процедурасынан қайтарылғаннан кейін BUF буферіне қабылданып және орналастырылатынына кепілдік береді.
int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int source, int msgtag, MPI_Comm comm, MPI_Status *status)
out buf — хабарламаны қабылдайтын буфердің басталу адресі;
count — қабылданатын хабарламадағы элементтердің максималды саны;
datatype — қабылданатын хабарламадағы элементтер типі;
source — процесс-жіберуші нөмірі;
msgtag — қабылданатын хабарлама идентификаторы;
comm —коммуникатор идентификаторы;
out status — қабылданған хабарламаның параметрлері.
source процесінен msgtag идентификаторымен бұғатталуымен хабарламаны қабылдау. Қабылданатын хабарламадағы элементтер саны count мәнінен асып кетпеу керек. Егер нақты қабылданған элементтер саны count мәнінен кіші болса, онда BUF буферінде тек қабылданған хабарлама элементтеріне сәйкес келетін элементтер ғана өзгеретініне кепілдік беріледі. Егер қабылданған хабарламадағы элементтердің дәл санын білу керек болса, онда MPI_Probe немесе MPI_Get_count функцияларын пайдалануға болады. Бұғатталу, хабарламаның барлық элементтері функциядан қайтарылғаннан кейін BUF буферіне қабылданып және орналастырылатынына кепілдік береді.
Төменде нөмірі нөлінші процесс нөмірі бірінші процеске хабарлама жіберетін және одан жауап күтетін бағдарлама мысалы Си және Фортран тілдерінде келтірілген.
Си тіліндегі нұсқасы.
#include "mpi.h"
#include <stdio.h>
int main(argc,argv)
int argc;
char *argv[]; {
int numtasks, rank, dest, src, rс, tag=l;
char inmsg, outmsg='x';
MPI_Status Stat;
MPI_Init(&argc,&argv);
MPI_Comm_size(MPI_COMM_WORLD, &numtasks);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
if (rank ==0) {
dest = 1;
src = 1;
rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
rc = MPI_Recv(&inmsg,1,MPI_CHAR, src, tag, MPI_COMM_WORLD, &Stat);
}
else
if (rank == 1) {
dest = 0;
src = 0;
rc = MPI_Recv(&inmsg, 1, MPI_CHAR, src, tag, MPI_COMM_WORLD, &Stat);
rc = MPI_Send(&outmsg, 1, MPI_CHAR, dest, tag, MPI_COMM_WORLD);
}
MPI_Finalize ();
}
Егер бағдарлама көп процестер санымен жіберілсе, онда жіберулерді нақты тек нөлінші және бірінші процестер ғана орындайды. MPI_Init функциясы орындалуынан туындаған қалған процестер MPI_Finalize функциясын орындап бірден аяқталады.
Фортран тіліндегі нұсқасы.
program example2
include 'mpif.h’
integer ierr, size, rank
real a, b
integer status(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
a = 0.0
b = 0.0
if(rank .eq. 0) then
b = 1.0
call MPI_SEND(b, 1, MPI_REAL, 1, 5, & MPI_COMM_WORLD, ierr);
call MPI_RECV(a, 1, MPI_REAL, 1, 5, & MPI_COMM_WORLD, status, ierr);
else
if(rank .eq. 1) then
a = 2.0
call MPI_RECV(b, 1, MPI_REAL, 0, 5, & MPI_COMM_WORLD, status, ierr);
call MPI_SEND(a, 1, MPI_REAL, 0, 5, & MPI_COMM_WORLD, ierr);
end if
end if
print *, 'process ', rank,’ a = ', a, ', b = ', b
call MPI_FINALIZE(ierr)
end
Мұнда да егер бағдарлама көп процестер санымен жіберілсе, онда жіберулерді нақты тек нөлінші және бірінші процестер ғана орындайды. MPI_Init функциясы орындалуынан туындаған қалған процестер a және b айнымалыларының бастапқы мәндерін баспаға беріп, одан кейін MPI_Finalize функциясын орындап аяқталады
Келесі мысалда жұп нөмірлі әрбір процесс нөмірі бірге артық өз көршілеріне хабарлама жібереді. Масималды нөмірлі процеске келесі жоқ процеске хабарлама жібермеу үшін қосымша тексеру қойылған. Бағдарламаның төменде сүлбесі ғана көрсетілген (Си тілінде).
main(int argc, char **argv)
{
int me, size;
int SOME_TAG=0;
MPI_Status status;
...
MPI_Init (&argc, &argv);
MPI_Comm_rank (MPI_COMM_WORLD, &me);
MPI_Comm_size (MPI_COMM_WORLD, &size);
If( (me % 2) == 0) {
if((me+1)< size) /* соңғысынан басқа процестердің бәрін жібереді */
MPI_Send (..., me+1, SOME_TAG, MPI_COMM_WORLD);
}
else
MPI_Recv (..., me-1, SOME_TAG, MPI_COMM_WORLD, &status);
...
MPI_Finalize();
}
Фортран тіліндегі нұсқасы
program example3
include 'mpif.h'
integer ierr, size, rank, a, b
integer status(MPI_STATUS_SIZE)
call MPI_INIT(ierr)
call MPI_COMM_SIZE(MPI_COMM_WORLD, size, ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
a = rank
b = -1
if(mod(rank, 2) .eq. 0) then
if(rank+1 .It. size) then
C соңғысынан басқа процестердің бәрін жібереді
call MPI_Send(a, 1, MPI_INTEGER, rank+1, 5,
& MPI_COMM_WORLD, ierr);
end if
else
call MPI_Recv(b, 1, MPI_INTEGER, rank-1, 5, & MPI_COMM_WORLD, status, ierr);
end if
print *, 'process ', rank,’ a = ', a, ', b = ', b
call MPI_FINALIZE(ierr)
end
Хабарламаны қабылдау кезінде source және msgtag аргументтерінің орнына алдын ала анықталған келесі тұрақтыларды пайдалануға болады:
mpi_any_source —кезкелген процестегі хабарлама сәйкестігінің белгісі;
mpi_any_tag — кезкелген идентификатормен хабарлама сәйкестігінің белгісі.
Бұл екі тұрақтыны бір мезгілде пайдалану кезінде кезкелген процестен кезкелген идентификатормен хабарлама қабылдауға болады.
Қабылданған хабарламаның нақты атрибутарын әрқашанда status массивінің сәйкес элементтерімен анықтауға болады. Фортранда status параметрі өлшемі mpi_status_size болатын бүтінсанды массив. mpi_source, mpi_tag және mpi_error тұрақтылары сәйкес өрістер мәндеріне қатынас үшін осы массив бойынша индекстер:
status(mpi_source) – хабарламаны процесс-жіберушінің нөмірі;
status(mpitag) – хабарлама идентификаторы;
status(MPl_ERROR) – қателік коды
Си тілінде status параметрі MPI_SOURCE, MPI_TAG және MPI_ERROR өрісімен алдын ала анықталған MPI_Status типті құрылым болады.
Хабарламаны жіберу және қабылдау операцияларының кейбір симметриялы еместігіне назар аударайық. mpi_any_source тұрақтысының көмегімен кезкелген процестен хабарлама қабылдауға болады. Алайда, деректерді жіберу кезінде қабылдаушы процестің нөмірін айқын түрде көрсету қажет.
Стандартта айтылған, егер бір процесс басқа процеске тізбектеп екі хабарлама жіберетін болса, және бұл екі хабарлама да MPI_Recv шақыруына сәйкес келсе, онда хабарламаның қайсысы ертерек жіберілсе сонысы бірінші болып қабылданады. Сонымен бірге, егер екі хабарлама бір мезгілде әртүрлі процестермен жіберілетін болса, онда оларды қабылдау реті қабылдаушы процеспен алдын ала анықталмаған.
MPI_GET_COUNT(STATUS, DATATYPE, COUNT, IERR)
INTEGER COUNT, DATATYPE, IERR, STATUS(MPI_STATUS_SIZE)
STATUS параметрінің мәні бойынша, процедура, қабылданған (MPI_Recv қатысуынан кейін) немесе қабылданатын (mpi_probe немесе mpi_iprobe қатысуынан кейін) DATATYPE типті хабарлама элементтері COUNT санын анықтайды. Бұл процедура, дербес жағдайда, қабылданатын хабарламаны сақтау үшін бөлінетін жады облысының өлшемін анықтау үшін қажет.
MPI_PROBE(SOURCE, MSGTAG, СОММ, STATUS, IERR)
INTEGER SOURCE, MSGTAG, COMM, IERR, STATUS(MPI_STATUS_SIZE)
COMM коммуникаторында SOURCE нөмірлі процестен MSGTAG идентификаторымен күтілетін бұғатталуымен хабарлама құрылымы туралы ақпаратты STATUS массивінде алу. Қашан хабарлама жарамды идентификаторымен және процесс-жіберуші нөмірімен қабылдау үшін қолжетімді болмайынша, процедурадан қайтарылым орын алмайды. Процедура хабарламаның келу фактін ғана анықтайтынын, бірақ оны нақты қабылдамайтынына аса назар аудару керек. Егер MPI_PROBE шақыруынан кейін дәл осындай параметрлерімен mpi_recv шақырылатын болса, онда MPI_PROBE процедурасын шақыру көмегімен ақпарат алынған дәл сол хабарлама қабылданады.
Келесі мысал келетін хабарламаның құрылымын анықтау үшін MPI_PROBE процедурасының қолданылуын көрсетеді. Процесс 0 кез-келген 1 және 2 (тегтері бірдей) процестерден келетін хабарламаны күтеді. Алайда, бұл процестерден жіберілетін деректер типтері әртүрлі. Келетін хабарламаны қай айнымалыға орналастыру керек екенін анықтау үшін, процесс алдымен MPI_PROBE шақыруының көмегімен хабарламаның кімнен келгенін анықтайды. Одан кейінгі mpi_recv шақыруы қажетті хабарламаны кепілді түрде қабылдайды. Соңынан басқа процестен хабарлама қабылданады (Фортран тіліндегі нұсқасы)
program example4
include 'mpif.h’
integer rank, ierr, ibuf, status(MPI_STATUS_SIZE)
real rbuf
call MPI_INIT(ierr)
call MPI_COMM_RANK(MPI_COMM_WORLD, rank, ierr)
ibuf = rank
rbuf = 1.0 * rank
if(rank .eq. 1) call MPI_SEND(ibuf, 1, MPI_INTEGER, 0, 5, & MPI_COMM_WORLD, ierr)
if(rank .eq. 2) call MPI_SEND(rbuf, 1, MPI_REAL, 0, 5, & MPI_COMM_WORLD, ierr)
if(rank .eq. 0) then
call MPI_PROBE(MPI_ANY_SOURCE, 5, MPI_COMM_WORLD, & status, ierr)
if(status(MPI_SOURCE) .EQ. 1) then
call MPI_RECV(ibuf, 1, MPI_INTEGER, 1, 5, & MPI_COMM_WORLD, status, ierr)
call MPI_RECV(rbuf, 1, MPI_REAL, 2, 5, & MPI_COMM_WORLD, status, ierr)
else
if(status(MPI_SOURCE) .EQ. 2) then
call MPI_RECV(rbuf, 1, MPI_REAL, 2, 5, & MPI_COMM_WORLD, status, ierr)
call MPI_RECV(ibuf, 1, MPI_INTEGER, 1, 5, & MPI_COMM_WORLD, status, ierr)
end if
end if
print *, 'Process 0 recv ', ibuf, ‘ from process 1, ', & rbuf, ' from process 2’
end if
call MPI_FINALIZE(ierr)
end
Бұғатталусыз хабарламаны қабылдау/жіберу.
Деректерді асинхронды жіберуді іске асыру үшін MPI технологиясында процедуралар жиынтығы қарастырылған. Бұғатталатын процедуралардан айырмашылығы, берілген топтағы процедуралардан қайтарылу процестер жұмысын тоқтатпай-ақ бірден шақырудан кейін іске асады. Бағдарламаның одан ары орындалуымен қатар бір мезетте асинхронды жіберілген операцияларға да өңдеу жүргізіледі.
Бұл мүмкіндік тиімді бағдарламалар құру үшін өте пайдалы десе болады. Шынында-да, бағдарламашы қандай да бір уақыт мезетінде оған басқа процесті есептейтін массив қажет екенін біледі. Сондықтан ол бұл массивті алу үшін бағдарламада алдын ала сұраныс жасап қоя алады, ал массив нақты керек болғанынша кезкелген басқа пайдалы жұмысты атқара алады. Көптеген жағдайларда келесі есептеулерді жүргізу үшін хабарлама жіберудің аяқталуын күтіудің қажеттілігі жоқ. Асинхронды алмасуды аяқтау үшін, операцияның аяқталғанын, болмаса оның аяқталуын күтіп тұрғанын тексеретін қосымша процедураны шақыру қажет етіледі. Содан кейін ғана жіберілетін хабарламаны бүлдіруден қорықпай, басқа мақсаттар үшін жіберу буферін пайдалануға болады.
Егер мүмкіндік болса хабарламаны қабылдау/жіберу операциясын есептеу фонында жасырып қою және осы мүмкіндікті қалайда пайдалану керек сияқты. Алайда тәжірибе жүзінде бәрі теориямен үйлесімді бола бермейді. Көп нәрсе нақты іске асыруларға байланысты. Өкінішке орай, жүйелік орта және аппаратура жағынан асинхронды операциялар әрқашанда тиімді қолдау таба бермейді. Сондықтан, егер жіберулер фонында есептеулерді орындау тиімділігі нөлге тең болса оған таңқалуға да болмайды.
Айтылған ескертулер тек тиімділік сұрақтарына ғана қатысты. Ал енді олардың ұсынатын функционалдығы жағынан қарайтын болсақ, асинхронды операциялар өте пайдалы, сол себепті олар әрбір нақты бағдарламада қатысады десек артық емес.
MPI_ISEND(BUF, COUNT, DATATYPE, DEST, MSGTAG, COMM, REQUEST,
IERR)
<type> BUF(*)