Какой смысл использовать MPI_Bcast, когда все ранги могут видеть данные, которые будут транслироваться?

Я просто думаю о причине использования MPI_Bcast, потому что, когда я не передаю целое число N всем рангам, они могут видеть N. Посмотрите на код и его результат. Как до, так и после трансляции целое число N видно всем рангам. так какой тут смысл? Кроме того, имеет ли смысл использование MPI_Bcast изменения порядка вызова каждого ранга?

#include <iostream>
#include "mpi.h"
using namespace std; 
int main()
{
   MPI_Init(NULL, NULL);
    int rank, size; 
    int N=9 ;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    cout << " Hello from rank : " << rank << " N is: " << N << endl;
    MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
    cout << " Hello from rank : " << rank << " N is: " <<N<<endl;
    MPI_Finalize();

}

Результат:

 Hello from rank : 1 N is: 9
 Hello from rank : 3 N is: 9
 Hello from rank : 0 N is: 9
 Hello from rank : 2 N is: 9
 Hello from rank : 0 N is: 9
 Hello from rank : 1 N is: 9
 Hello from rank : 2 N is: 9
 Hello from rank : 3 N is: 9

person MA19    schedule 06.03.2021    source источник


Ответы (2)


MPI_Bcast становится полезным в тех случаях, когда N в вашем примере на самом деле будет изменено рангом вещания. Вместо этого рассмотрите это:

#include <iostream>
#include "mpi.h"

using namespace std;

int main()
{
    MPI_Init(NULL, NULL);
    int rank, size;
    int N=9 ;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    cout << " Hello from rank : " << rank << " N is: " << N << endl;

    // Change N on the rank that will broadcast
    if (rank == 0) {
        N = 18;
    }

    MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
    cout << " Hello from rank : " << rank << " N is: " <<N<<endl;
    MPI_Finalize();
}

Ранг 0 изменил N и хочет отправить свое значение всем остальным рангам. Он может отправить его каждому рангу отдельно, используя MPI_Send. и MPI_Recv или может использовать некоторую форму коллективного общение, например MPI_Bcast.

Однако MPI_Bcast — правильный выбор, поскольку он оптимизирован для предоставляемой им функциональности: отправки информации от одного ко всем. Я советую вам проверить его алгоритм связи, чтобы понять.

Поскольку обмен данными является узким местом распараллеливания ЦП, необходимо тщательно выбирать алгоритмы обмена данными. Эмпирическое правило заключается в том, что все, что было разработано для коллективной связи, должно использоваться для этого, а не для подхода «точка-точка» с отправкой-получением (т. Е. Ранг 0 отправляет друг другу ранг индивидуально).

Вещание «один ко всем» на самом деле является обычной ситуацией на практике, по крайней мере, в научных вычислениях, когда, например, одному рангу необходимо прочитать входные параметры, подготовить основания для моделирования, а затем передать некоторую необходимую информацию всем остальным рангам. Вещание также может потребоваться во время вычислений, когда один ранг должен делиться своими результатами с подмножеством других или со всеми.

person atru    schedule 06.03.2021
comment
Спасибо! очень полезный. Еще одна вещь, первый аргумент MPI_Bcast, который является буфером, в котором N существует. Означает ли это, что другие процессоры будут искать адрес N в ранге 0 и копировать значение N в свою память? - person MA19; 06.03.2021
comment
С удовольствием :) Я так не думаю, MPI использует распределенную память, эти ранги могут быть на разных узлах - эквивалентно полностью разделенным компьютерам, с разной памятью, даже расположением памяти. Bcast отправит значение N всем рангам, а затем каждый сохранит значение в своем собственном N. Bcast также можно использовать для массивов, и я предполагаю, что принцип тот же, он отправляет значения, а не указатели на отправителя. объем памяти. - person atru; 06.03.2021
comment
Да, ты прав. но использование & перед N ввело меня в заблуждение. Я думал, что адрес широковещательный, что не имеет смысла - person MA19; 06.03.2021
comment
Я вижу, все коммуникации MPI используют указатели в качестве аргументов, возможно, чтобы сделать функциональность явно ясной/одинаковой как для значений, так и для массивов. И эффективный. Вы также можете быстро ознакомиться с парадигмой распределенной памяти, она становится яснее, если сравнить с распараллеливанием разделяемой памяти, как в многопоточности OpenMP. Это на самом деле интересно, тогда потоки-ранги работали бы буквально на одном и том же бите памяти. - person atru; 06.03.2021

В вашем примере значение жестко закодировано. Нет смысла транслировать значение, которое уже известно.

Что, если бы он был рассчитан, скажем, в ранге 0 после запуска? Затем MPI_Bcast можно использовать для трансляции на все остальные ранги.

    MPI_Init(NULL, NULL);
    int rank, size; 
    int N = 0;
    MPI_Comm_rank(MPI_COMM_WORLD, &rank);
    MPI_Comm_size(MPI_COMM_WORLD, &size);
    cout << " Hello from rank : " << rank << " N is: " << N << endl;
    if (rank == 0) {
        N = 9;
    }
    MPI_Bcast(&N, 1, MPI_INT, 0, MPI_COMM_WORLD);
    cout << " Hello from rank : " << rank << " N is: " <<N<<endl;
    MPI_Finalize();

Отпечатки:

 Hello from rank : 0 N is: 0
 Hello from rank : 3 N is: 0
 Hello from rank : 2 N is: 0
 Hello from rank : 1 N is: 0
 Hello from rank : 0 N is: 9
 Hello from rank : 1 N is: 9
 Hello from rank : 2 N is: 9
 Hello from rank : 3 N is: 9
person rustyx    schedule 06.03.2021