Отправка данных работникам

Я пытаюсь создать кусок параллельного кода, чтобы ускорить обработку очень большого (пара сотен миллионов строк) массивов. Чтобы распараллелить это, я разбил свои данные на 8 (количество ядер) частей и попытался отправить каждому работнику по 1 части. Однако, глядя на использование моей оперативной памяти, кажется, что каждая часть отправляется каждому работнику, эффективно умножая использование моей оперативной памяти на 8. Минимальный рабочий пример:

A = 1:16;
for ii = 1:8
    data{ii} = A(2*ii-1:2*ii);
end

Теперь, когда я отправляю эти данные работникам, использующим parfor кажется, что отправляется полная ячейка, а не только нужный кусок:

output = cell(1,8);
parfor ii = 1:8
    output{ii} = data{ii};
end

Я на самом деле использую какую-то функцию в parfor цикл, но это иллюстрирует случай. Действительно ли MATLAB отправляет полную ячейку data каждому работнику, и если да, то как заставить его отправлять только нужный кусок?

3 ответа

Решение

По своему личному опыту я обнаружил, что используя parfeval лучше в отношении использования памяти, чем parfor, Кроме того, ваша проблема кажется более решаемой, поэтому вы можете использовать parfeval за предоставление более мелких рабочих мест работникам MATLAB.

Допустим, у вас есть workerCnt Работники MATLAB, с которыми ты будешь обращаться jobCnt рабочие места. Позволять data быть размером с ячейку jobCnt x 1и каждый из его элементов соответствует вводу данных для функции getOutput который делает анализ данных. Результаты затем сохраняются в массиве ячеек output размера jobCnt x 1,

в следующем коде задания назначаются в первом for цикл и результаты извлекаются во втором while петля. Булева переменная doneJobs указывает, какая работа выполнена.

poolObj = parpool(workerCnt);
jobCnt = length(data); % number of jobs
output = cell(jobCnt,1);
for jobNo = 1:jobCnt
    future(jobNo) = parfeval(poolObj,@getOutput,...
        nargout('getOutput'),data{jobNo});
end
doneJobs = false(jobCnt,1);
while ~all(doneJobs)
    [idx,result] = fetchnext(future);
    output{idx} = result;
    doneJobs(idx) = true;
end

Кроме того, вы можете сделать этот подход еще на шаг дальше, если хотите сэкономить больше памяти. Что вы можете сделать, так это то, что после извлечения результатов выполненной работы вы можете удалить соответствующий элемент future, Причина в том, что этот объект хранит все входные и выходные данные getOutput функция, которая, вероятно, будет огромной. Но нужно быть осторожным, так как удаляя членов future сдвиг индекса результатов.

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

poolObj = parpool(workerCnt);
jobCnt = length(data); % number of jobs
output = cell(jobCnt,1);
for jobNo = 1:jobCnt
    future(jobNo) = parfeval(poolObj,@getOutput,...
        nargout('getOutput'),data{jobNo});
end
doneJobs = false(jobCnt,1);
while ~all(doneJobs)
    [idx,result] = fetchnext(future);
    furure(idx) = []; % remove the done future object
    oldIdx = 0;
    % find the index offset and correct index accordingly
    while oldIdx ~= idx
        doneJobsInIdxRange = sum(doneJobs((oldIdx + 1):idx));
        oldIdx = idx
        idx = idx + doneJobsInIdxRange;
    end
    output{idx} = result;
    doneJobs(idx) = true;
end

Комментарий от @ms правильный - когда parfor разрезает массив, затем каждому рабочему отправляется только тот фрагмент, который необходим для итераций цикла, над которыми он работает. Тем не менее, вы можете увидеть увеличение использования ОЗУ сверх того, что вы изначально ожидали, поскольку, к сожалению, требуются копии данных, так как они передаются от клиента к работникам через parfor механизм связи.

Если вам нужны данные только о работниках, то лучшим решением будет создание / загрузка / доступ к ним только по работникам, если это возможно. Похоже, вы после параллелизма данных, а не параллелизма задач, для которых spmd действительно лучше подходит (как предполагает @Kostas).

Я бы предложил использовать spmd команда MATLAB.

Вы можете написать код почти так же, как это было бы для непараллельной реализации, а также иметь доступ к текущему работнику с помощью labindex системная переменная.

Посмотрите здесь:

http://www.mathworks.com/help/distcomp/spmd.html

А также на этот так вопрос о spmd против parfor:

SPMD vs. Parfor

Другие вопросы по тегам