2016-06-20 2 views
1

Использование C++ и OpenMPI Я хотел бы создать вектор, а затем в основном процессе распределить части вектора равномерно подчиненным процессам, которые будут обрабатываться. Поэтому, если вектор имеет 100 целых чисел и существует 5 подчиненных процессов, каждому подчиненному процессу будет отправлен вектор из 20 целых чисел.Распространение части вектора на подчиненные процессы

Ниже приведен код, который я пытался, но он не работает.

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
int rank, size, tag, rc, i; 
MPI_Status status; 
vector<int> vec(100); 
vector<int> split_vec; 

rc = MPI_Init(&argc, &argv); 
rc = MPI_Comm_size(MPI_COMM_WORLD, &size); 
rc = MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
tag=7; 

random_device rd; 
mt19937 gen(rd()); 
uniform_int_distribution<> dis; 
generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
// 100 ints/5 slave processes 
int split_size = vec.size()/size; 
// split_size = size of vector of ints that each slave process should get 
int offset = 0; 
int j = 0; 
int max = split_size; 
if (rank==0) { 
// master process 
    for (int i=1; i<size; ++i){ 
      split_vec.clear(); 
      while(j < max){ 
       int elements = i_j + offset; 
       split_vec.push_back(vec[elements]); 
       j++; 
      } 
      max = max + split_size; 
      offset = offset + split_size; 
    MPI_Send(&split_vec[0], split_vec.size(), MPI_INT, i, tag, MPI_COMM_WORLD); 
else{ 
    // slaves processes 
    MPI_Recv(&split_vec[0], split_vec.size(), MPI_INT, 0, tag, MPI_COMM_WORLD, &status); 
    // process the vector 
} 
    MPI_Finalize(); 
}// main 

Когда я запускаю код выше, я получаю следующее сообщение об ошибке:

[comp-01:7562] *** An error occurred in MPI_Recv 
[comp-01:7562] *** on communicator MPI_COMM_WORLD 
[comp-01:7562] *** MPI_ERR_TRUNCATE: message truncated 
[comp-01:7562] *** MPI_ERRORS_ARE_FATAL: your MPI job will now abort 

Это, кажется, работает это путь через vector<int> vec(100) вектор правильно, схватив первые двадцать целых чисел, рядом двадцать и т.д. Но я думаю, что это сбой, потому что я продолжаю перезаписывать элементы в split_vec, и значения гаража приводят к его сбою. Когда я печатаю векторы, потому что я отправляю их ниже, это то, что напечатано до того, как оно сработает.

0 64 0 33 0 1819240283 808662067 976302125 892679984 2121015 0 49 0 -773125744 32554 0 0 -773125760 32554 0 0 

Даже если нет 0 или отрицательных чисел в vec векторе. Поэтому я попытался исправить это, добавив код split_vec.clear();, но это тоже не работает.

Ниже я использовал его для компиляции и запуска.

mpic++ -std=c++11 prog.cpp -o prog.o 
mpirun -np 6 prog.o // 5 slave process 

ответ

1

следующие изменения необходимы для того, чтобы сделать MPI_Recv() успешным:

  • В коде вы в курсе, split_vec.size() 0 в MPI_Recv() так split_vec еще не заселена. Следовательно, MPI_Recv() получит сообщение, но вектор не будет изменен.

  • Первый буфер приема должен быть выделен. В данном случае это означает, что до звонка до MPI_Recv(&split_vec[0],MPI_INT,split_size,...); необходимо добавить split_vec.reserve(split_size);. Действительно, способ vector::reserve(size_type n) увеличит пропускную способность вектора по меньшей мере до n элементов. Как заметил @Zulan, использование split_vec.resize(split_size); вернее, так как оно также обновляет размер вектора.

Наконец, следующий код делает трюк:

split_vec.resize(split_size); 
MPI_Recv(&split_vec[0],MPI_INT,split_vec.size(),...); 

Вот исправленный код. Обратите внимание, что индексы, используемые для заполнения массива в ранге 0, должны были быть изменены. Компиляция его mpiCC main.cpp -o main -std=c++11 -Wall

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
    int rank, size, tag; 
    MPI_Status status; 
    vector<int> vec(100); 
    vector<int> split_vec; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 
    tag=7; 

    random_device rd; 
    mt19937 gen(rd()); 
    uniform_int_distribution<> dis; 
    generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
    // 100 ints/5 slave processes 
    int split_size = vec.size()/size; 
    // split_size = size of vector of ints that each slave process should get 
    int offset = 0; 
    if (rank==0) { 
     // master process 
     for (int i=1; i<size; ++i){ 
      split_vec.clear(); 
      split_vec.reserve(split_size); 
      int j=0; // added j=0 
      while(j < split_size){ 
       int elements = j + offset; 
       split_vec.push_back(vec[elements]); 
       j++; 
      } 
      //max = split_size; 
      offset = offset + split_size; 
      MPI_Send(&split_vec[0], split_vec.size(), MPI_INT, i, tag, MPI_COMM_WORLD); 
     } 
    } 
    else{ 
     // slaves processes 
     split_vec.resize(split_size); 
     MPI_Recv(&split_vec[0], split_vec.size(), MPI_INT, 0, tag, MPI_COMM_WORLD, &status); // until receive is complete, split_vec.size()==0 
    } 
    MPI_Finalize(); 
}// main 

Наконец, вы собираетесь пользоваться функцией MPI_Scatter() который точно делает то, что вы хотите сделать!

#include <iostream> 
#include <list> 
#include "mpi.h" 
#include <stdio.h> 
#include <stdlib.h> 
#include <vector> 
#include <algorithm> 
#include <map> 
#include <random> 

using namespace std; 

int main(int argc, char **argv) 
{ 
    int rank, size; 

    vector<int> vec(100); 
    vector<int> split_vec; 

    MPI_Init(&argc, &argv); 
    MPI_Comm_size(MPI_COMM_WORLD, &size); 
    MPI_Comm_rank(MPI_COMM_WORLD, &rank); 

    random_device rd; 
    mt19937 gen(rd()); 
    uniform_int_distribution<> dis; 
    generate(vec.begin(), vec.end(), [&](){ return dis(gen); }); 
    // 100 ints/5 slave processes 
    int split_size = vec.size()/size; 
    // split_size = size of vector of ints that each slave process should get 


    split_vec.resize(split_size); 
    MPI_Scatter(&vec[0],split_size,MPI_INT,&split_vec[0],split_size,MPI_INT,0,MPI_COMM_WORLD); 

    MPI_Finalize(); 
}// main 
+1

Вы не можете использовать здесь 'std :: vector :: reserve'! Хотя это не приведет к сбою, вектор по-прежнему будет иметь «размер» 0 после вызова 'MPI_Recv' /' MPI_Scatter'! Вместо этого используйте 'resize'. – Zulan

+1

"количество отправленных предметов должно соответствовать количеству подлежащих получению предметов" Это неверно. Стандарт (3.2.4) требует только: «Длина принятого сообщения должна быть меньше или равна ** длине буфера приема». – Zulan

+0

@ Zulan: спасибо за то, что я указал на эти ошибки в своем ответе! У меня еще есть много вещей, чтобы узнать о MPI ... – francis

Смежные вопросы