У меня есть последовательная программа на C++, которую я хочу распараллелить. Я знаю основы MPI, MPI_Send
, MPI_Recv
и т. Д. В принципе, у меня есть алгоритм генерации данных, который работает значительно быстрее, чем алгоритм обработки данных. В настоящее время они запускаются последовательно, но я думал, что запуск генерации данных в корневом процессе, обработка данных выполняется на подчиненных процессах и отправка сообщения от корня к ведомому, содержащему данные, подлежащие обработке. Таким образом, каждое подчиненное устройство обрабатывает набор данных, а затем ожидает его следующего набора данных.MPI Ведомые процессы зависают, когда больше нет работы
Проблема заключается в том, что после того, как корень процесса выполняется с генерированием данных, программа зависает, потому что ведомые ждут больше.
Это пример задачи:
#include "mpi.h"
#include <cassert>
#include <cstdio>
class Generator {
public:
Generator(int min, int max) : value(min - 1), max(max) {}
bool NextValue() {
++value;
return value < max;
}
int Value() { return value; }
private:
int value, max;
Generator() {}
Generator(const Generator &other) {}
Generator &operator=(const Generator &other) { return *this; }
};
long fibonnaci(int n) {
assert(n > 0);
if (n == 1 || n == 2) return 1;
return fibonnaci(n-1) + fibonnaci(n-2);
}
int main(int argc, char **argv) {
MPI_Init(&argc, &argv);
int rank, num_procs;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &num_procs);
if (rank == 0) {
Generator generator(1, 2 * num_procs);
int proc = 1;
while (generator.NextValue()) {
int value = generator.Value();
MPI_Send(&value, 1, MPI_INT, proc, 73, MPI_COMM_WORLD);
printf("** Sent %d to process %d.\n", value, proc);
proc = proc % (num_procs - 1) + 1;
}
} else {
while (true) {
int value;
MPI_Status status;
MPI_Recv(&value, 1, MPI_INT, 0, 73, MPI_COMM_WORLD, &status);
printf("** Received %d from process %d.\n", value, status.MPI_SOURCE);
printf("Process %d computed %d.\n", rank, fibonnaci(2 * (value + 10)));
}
}
MPI_Finalize();
return 0;
}
Очевидно, что не все, что выше «хорошая практика», но достаточно, чтобы получить точку в поперечнике.
Если я удалю while(true)
из подчиненных процессов, программа выйдет, когда выйдут все подчиненные устройства. Я хотел бы, чтобы программа выходила только после того, как корневой процесс выполнил свою работу, и все подчиненные обработали все, что было отправлено.
Если бы я знал, сколько наборов данных будет сгенерировано, я мог бы запустить этот процесс, и все будет нормально работать, но это не так.
Любые предложения? Есть ли что-нибудь в API, который это сделает? Может ли это быть лучше с лучшей топологией? Будет ли MPI_Isend
или MPI_IRecv
сделать это лучше? Я довольно новичок в MPI, так что несите меня.
Благодаря
Реализация фибоначчи - это O (2^n).Вы должны оптимизировать свой последовательный алгоритм. – mfontanini
Я знаю. это не настоящая проблема, которую я решаю, это просто самый простой пример, который я мог бы подумать о том, что смоделировала проблему. –
Возможно, мне что-то не хватает, но не будет ли простой барьер в конце каждого процесса решить вашу проблему? – suszterpatt