У меня есть программа C ++ MPI, которая работает в кластере Windows HPC (12 узлов, 24 ядра на узел).
- Логика программы действительно проста:
- есть пул задач
- В начале программа делит задачи поровну на каждый процесс MPI
- Каждый процесс MPI выполняет свои задачи
- После того, как все будет завершено, используйте MPI Reduce для сбора результатов в корневой процесс.
Есть одна проблема. Каждое задание может иметь разное время выполнения, и я никак не могу сказать об этом заранее. Равное распределение задачи приведет к множеству процессов, ожидающих простоя. Это тратит много компьютерных ресурсов и увеличивает общее время выполнения.
Я думаю об одном решении, которое могло бы работать.
- Процесс такой.
- Пул задач делится на небольшие участки (например, 10 заданий)
- Каждый процесс MPI принимает посылку в момент простоя (не получил посылку или завершил предыдущую посылку)
- Шаг 2 продолжается до исчерпания пула задач
- Использование MPI Reduce для сбора всех результатов в корневой процесс
Насколько я понимаю, для этой схемы нужен универсальный счетчик между узлами / процессом (чтобы избежать, чтобы разные процессы MPI выполняли одну и ту же посылку), а для его изменения необходим некоторый механизм блокировки / синхронизации. Это, безусловно, имеет свои накладные расходы, но при правильной настройке, я думаю, это может помочь улучшить производительность.
Я не совсем знаком с MPI и имею некоторые проблемы с реализацией. Я могу придумать два способа реализации этого универсального счетчика
- Используя технику ввода / вывода MPI, запишите этот счетчик в файл, когда посылка будет взята, увеличьте этот счетчик (безусловно, потребуется механизм блокировки файла)
- Использование MPI односторонней связи / общей памяти. Поместите этот счетчик в общую память и увеличьте его при получении посылки. (непременно понадобится механизм синхронизации)
К сожалению, я не знаком ни с какой техникой, и хочу изучить возможность, реализацию или возможные недостатки двух вышеупомянутых методов. Пример кода будет принята с благодарностью.
Если у вас есть другие способы решения проблемы или предложения, это тоже будет здорово. Спасибо.
прослеживание:
Спасибо за все полезные предложения. Я реализовал тестовую программу по схеме использования процесса 0 в качестве распределителя задач.
#include <iostream>
#include <mpi.h>
using namespace std;
void doTask(int rank, int i){
cout<<rank<<" got task "<<i<<endl;
}
int main ()
{
int numTasks = 5000;
int parcelSize = 100;
int numParcels = (numTasks/parcelSize) + (numTasks%parcelSize==0?0:1);
//cout<<numParcels<<endl;
MPI_Init(NULL, NULL);
int rank, nproc;
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Comm_size(MPI_COMM_WORLD, &nproc);
MPI_Status status;
MPI_Request request;
int ready = 0;
int i = 0;
int maxParcelNow = 0;
if(rank == 0){
for(i = 0; i <numParcels; i++){
MPI_Recv(&ready, 1, MPI_INT, MPI_ANY_SOURCE, MPI_ANY_TAG, MPI_COMM_WORLD, &status);
//cout<<i<<"Yes"<<endl;
MPI_Send(&i, 1, MPI_INT, status.MPI_SOURCE, 0, MPI_COMM_WORLD);
//cout<<i<<"No"<<endl;
}
maxParcelNow = i;
cout<<maxParcelNow<<" "<<numParcels<<endl;
}else{
int counter = 0;
while(true){
if(maxParcelNow == numParcels) {
cout<<"Yes exiting"<<endl;
break;
}
//if(maxParcelNow == numParcels - 1) break;
ready = 1;
MPI_Send(&ready, 1, MPI_INT, 0, 0, MPI_COMM_WORLD);
//cout<<rank<<"send"<<endl;
MPI_Recv(&i, 1, MPI_INT, 0, 0, MPI_COMM_WORLD, &status);
//cout<<rank<<"recv"<<endl;
doTask(rank, i);
}
}
MPI_Bcast(&maxParcelNow, 1, MPI_INT, 0, MPI_COMM_WORLD);
MPI_Finalize();
return 0;
}
Это не работает и никогда не останавливается. Любые предложения о том, как заставить это работать? Этот код отражает идею правильно или я что-то упустил? Спасибо