У меня довольно длинный цикл parfor
(скажем, 100 000 итераций, где каждая итерация занимает около минуты), что я работаю с 36 ядрами. Я заметил, что в конце работы большое количество ядер простаивает, а некоторые заканчивают то, что, по моему мнению, должно быть несколькими итерациями на одного работника. Это приводит к большому количеству потраченного впустую вычислительного времени, ожидая, пока один работник закончит несколько заданий, в то время как остальные сидят без дела.Почему графический планировщик Matlab оставляет рабочих бездействующим?
Следующий сценарий показывает проблему (с помощью файла обмена утилита Par.m
):
% Set up parallel pool
nLoop = 480;
p1 = gcp;
% Run a loop
pclock = Par(nLoop);
parfor iLoop = 1:nLoop
Par.tic;
pause(0.1);
pclock(iLoop) = Par.toc;
end
stop(pclock);
plot(pclock);
% Process the timing info:
runs = [[pclock.Worker]' [pclock.ItStart]' [pclock.ItStop]'];
nRuns = arrayfun(@(x) sum(runs(:,1) == x), 1:max(runs));
starts = nan(max(nRuns), p1.NumWorkers);
ends = nan(max(nRuns), p1.NumWorkers);
for iS = 1:p1.NumWorkers
starts(1:nRuns(iS), iS) = sort(runs(runs(:, 1) == iS, 2));
ends(1:nRuns(iS), iS) = sort(runs(runs(:, 1) == iS, 3));
end
firstWorkerStops = min(max(ends));
badRuns = starts > firstWorkerStops;
nBadRuns = sum(sum(badRuns)) - (p1.NumWorkers-1);
fprintf('At least %d (%3.1f%%) iterations run inefficiently.\n', ...
nBadRuns, nBadRuns/nLoop * 100);
Путь я смотрю на него, каждый работник должен быть занят до тех пор, пока очередь не пуста, после чего все рабочие сидеть без дела. Но здесь похоже, что этого не происходит - с 480 итерациями я получаю между 6-20 итерациями, которые начинаются с рабочего, после того, как другой рабочий сидел без дела для полного цикла. Это число, по-видимому, масштабируется линейно, число итераций цикла составляет около 2% от общего числа. При ограниченном тестировании это, по-видимому, согласуется с Matlab 2016b и 2014b.
Есть ли причина, по которой это ожидаемое поведение, или это просто плохо написанный планировщик в реализации parfor
? Если да, то как я могу структурировать это, так что я не сижу с простаивающими рабочими так долго?
Как бы вы выполняли явное планирование с помощью 'spmd'? Я думаю, что я написал пример, но, похоже, он сталкивается с той же проблемой, что и «parfor». –
Конструкция 'for-drange' просто делит итерации цикла на куски одинакового размера, вот что я имел в виду. Это нормально, если каждая итерация занимает столько же времени. – Edric