2015-05-16 2 views
3

У меня есть много подчиненных узлов, которые могли или не могли отправлять сообщения на главный узел. Таким образом, в настоящее время мастер-узел не знает, сколько MPI_Recv ожидает. По соображениям эффективности ведомые узлы должны были отправить минимальное количество сообщений на главный узел.MPI: Что делать, когда число ожидаемых MPI_Recv не указано

Мне удалось найти a cool trick, который отправляет дополнительное сообщение «done», когда он больше не ожидает сообщений. К сожалению, это не работает в моем случае, где есть переменное количество отправителей. Любая идея о том, как это сделать? Благодаря!

if(rank == 0){ //MASTER NODE 

    while (1) { 

     MPI_Recv(&buffer, 10, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 

     if (status.MPI_TAG == DONE) break; 


     /* Do stuff */ 
    } 

}else{ //MANY SLAVE NODES 

    if(some conditions){ 
     MPI_Send(&buffer, 64, MPI_INT, root, 1, MPI_COMM_WORLD); 
    } 

} 


MPI_Barrier(MPI_COMM_WORLD); 
MPI_Send(NULL, 1, MPI_INT, root, DONE, MPI_COMM_WORLD); 

Не работает, кажется, программа будет по-прежнему ждет MPI_RECV

+0

Просто попробовал, я думаю, MPI_Barrier это выполняется, но 'не после того, как barrier' сообщение никогда не печатается, так как программа застрять на MPI_Recv – kornesh

+0

Rank 0 никогда не называет Барьер так явно висит. Удалите барьер, и он запустится. – Jeff

+0

Он фактически запускался без остановки, но затем он выполняет «MPI_Send» (NULL, 1, MPI_INT, root, DONE, MPI_COMM_WORLD); «сразу после первого подчиненного узла выполняется вычисление ... без ожидания других подчиненных узлов – kornesh

ответ

0

1- вы назвали MPI_Barrier в неправильном месте, он должен быть вызван после MPI_Send.
2- корень выйдет из цикла, когда он получит DONE из всех других рангов (размер -1).

код после некоторых модификаций:

#include <mpi.h> 
#include <stdlib.h> 
#include <stdio.h> 

int main(int argc, char** argv) 
{ 

    MPI_Init(NULL, NULL); 
    int size; 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    int rank; 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    MPI_Status status; 
    int DONE = 888; 
    int buffer = 77; 
    int root = 0 ; 
    printf("here is rank %d with size=%d\n" , rank , size);fflush(stdout); 
    int num_of_DONE = 0 ; 
if(rank == 0){ //MASTER NODE 


    while (1) { 

     MPI_Recv(&buffer, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status); 
     printf("root recev %d from %d with tag = %d\n" , buffer , status.MPI_SOURCE , status.MPI_TAG);fflush(stdout); 

     if (status.MPI_TAG == DONE) 
     num_of_DONE++; 
    printf("num_of_DONE=%d\n" , num_of_DONE);fflush(stdout); 
    if(num_of_DONE == size -1) 
     break; 



     /* Do stuff */ 
    } 

}else{ //MANY SLAVE NODES 

    if(1){ 
     buffer = 66; 
     MPI_Send(&buffer, 1, MPI_INT, root, 1, MPI_COMM_WORLD); 
     printf("rank %d sent data.\n" , rank);fflush(stdout); 
    } 

} 

    if(rank != 0) 
    { 
     buffer = 55; 
     MPI_Send(&buffer, 1, MPI_INT, root, DONE, MPI_COMM_WORLD); 
    } 


    MPI_Barrier(MPI_COMM_WORLD); 
    printf("rank %d done.\n" , rank);fflush(stdout); 
    MPI_Finalize(); 
    return 0; 
} 

выход:

[email protected]:~/Desktop$ mpicc -o aa aa.c 
    [email protected]:~/Desktop$ mpirun -n 3 ./aa 
here is rank 2 with size=3 
here is rank 0 with size=3 
rank 2 sent data. 
here is rank 1 with size=3 
rank 1 sent data. 
root recev 66 from 1 with tag = 1 
num_of_DONE=0 
root recev 66 from 2 with tag = 1 
num_of_DONE=0 
root recev 55 from 2 with tag = 888 
num_of_DONE=1 
root recev 55 from 1 with tag = 888 
num_of_DONE=2 
rank 0 done. 
rank 1 done. 
rank 2 done. 
+0

Я просто попробовал ваш подход, к сожалению, он прекратился раньше, чем следовало бы. Каждый подчиненный узел занимает свое собственное время для выполнения своих вычислений, последний узел в сетке не означает, что он должен заканчиваться последним. Я думаю, что 'sleep (1)' будет делать трюк, если последний процесс занимает менее 1 секунды для вычисления. – kornesh

+0

@kornesh: Я изменил ответ. – houssam

+0

Thats элегантный способ, но _Slave узлы должны были отправить минимальное количество сообщений на главный узел по причинам эффективности. – kornesh

2

Более простой и элегантный вариант будет использовать MPI_IBARRIER. Попросите каждого рабочего вызвать все отправленные ему сообщения, а затем позвонить MPI_IBARRIER, когда это будет сделано. На главном вы можете наложить как на MPI_IRECV на MPI_ANY_SOURCE, так и на номер MPI_IBARRIER. Когда закончится MPI_IBARRIER, вы знаете, что все закончили, и вы можете отменить MPI_IRECV и двигаться дальше. Псевдокод будет выглядеть примерно так:

if (master) { 
    /* Start the barrier. Each process will join when it's done. */ 
    MPI_Ibarrier(MPI_COMM_WORLD, &requests[0]); 

    do { 
    /* Do the work */ 
    MPI_Irecv(..., MPI_ANY_SOURCE, &requests[1]); 

    /* If the index that finished is 1, we received a message. 
    * Otherwise, we finished the barrier and we're done. */ 
    MPI_Waitany(2, requests, &index, MPI_STATUSES_IGNORE); 
    } while (index == 1); 

    /* If we're done, we should cancel the receive request and move on. */ 
    MPI_Cancel(&requests[1]); 
} else { 
    /* Keep sending work back to the master until we're done. */ 
    while(...work is to be done...) { 
    MPI_Send(...); 
    } 

    /* When we finish, join the Ibarrier. Note that 
    * you can't use an MPI_Barrier here because it 
    * has to match with the MPI_Ibarrier above. */ 
    MPI_Ibarrier(MPI_COMM_WORLD, &request); 
    MPI_Wait(&request, MPI_STATUS_IGNORE); 
} 
Смежные вопросы