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

Я пытаюсь создать кусок параллельного кода, чтобы ускорить обработку большого массива (пару сотен миллионов строк). Чтобы распараллелить это, я расколол свои данные на 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 каждому работнику, и если да, то как заставить ее отправлять только желаемую часть?

Ответ 1

В моем личном опыте я обнаружил, что использование 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 изменяется.

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

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

Ответ 2

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

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

Ответ 3

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

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

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

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

И также при этом SO вопрос о spmd vs parfor:

SPMD против Parfor