Я пишу код MatLab для выполнения 3 мерного интеграла: сПочему пакетный режим намного быстрее, чем parfor?
function [ fint ] = int3d_ser(R0, Rf, N)
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
fint = 0.0;
for ir = 2:Nr
r = rs(ir);
r2dr = r*r*dr;
for it = 1:Nt-1
t = ts(it);
sintdt = sin(t)*dt;
for ip = 1:Np-1
p = ps(ip);
fint = fint + C*r2dr*sintdt*dp;
end
end
end
end
для ассоциированного int3d_par
(parfor) версии, открываю бассейн MatLab и просто заменить for
с parfor
. Я получаю довольно приличное ускорение, и я запускаю его на большее количество ядер (мои тесты от 2 до 8 ядер).
Однако, когда я запускаю же интеграцию в пакетном режиме с:
function [fint] = int3d_batch_cluster(R0, Rf, N, cluster, ncores)
%%% note: This will not give back the same value as the serial or parpool version.
%%% If this was a legit integration, I would worry more about even dispersion
%%% of integration nodes per core, but I just want to benchmark right now so ... meh
Nr = N;
Nt = round(pi*N);
Np = round(2*pi*N);
rs = linspace(R0, Rf, Nr);
ts = linspace(0, pi, Nt);
ps = linspace(0, 2*pi, Np);
dr = rs(2)-rs(1);
dt = ts(2)-ts(1);
dp = ps(2)-ps(1);
C = 1/((4/3)*pi);
rns = floor(Nr/ncores)*ones(ncores,1);
RNS = zeros(ncores,1);
for icore = 1:ncores
if(sum(rns) ~= Nr)
rns(icore) = rns(icore)+1;
end
end
RNS(1) = rns(1);
for icore = 2:ncores
RNS(icore) = RNS(icore-1)+rns(icore);
end
rfs = rs(RNS);
r0s = zeros(ncores,1);
r0s(2:end) = rfs(1:end-1);
j = createJob(cluster);
for icore = 1:ncores
r0 = r0s(icore);
rf = rfs(icore);
rn = rns(icore);
trs = linspace(r0, rf, rn);
t{icore} = createTask(j, @int3d_ser, 1, {r0, rf, rn});
end
submit(j);
wait(j);
fints = fetchOutputs(j);
fint = 0.0;
for ifint = 1:length(fints)
fint = fint + fints{ifint};
end
end
Я заметил, что это гораздо, гораздо быстрее. Зачем делать эту интеграцию в пакетном режиме, чем делать это в parfor
?
Для справки, я тестирую код с N
от небольших чисел, таких как 10 и 20 (для получения константы в полиномиальной аппроксимации времени выполнения) для больших чисел, таких как 1000 и 2000. Этот алгоритм будет масштабироваться по шкале, поскольку я назначаю число узлов интеграции в направлениях theta
и phi
должно быть постоянным кратным заданного N
.
Для узлов в 2000 году версия parfor
занимает около 630 секунд, тогда как то же количество узлов в пакетном режиме занимает около 19 секунд (где около 12 секунд - это просто служебная связь, которую мы также получаем для 10 узлов интеграции).
Какой тип '' вы заменяете 'parfor'? Это может повлиять на эту структуру вложенных циклов (например, нанести удар по «parfor» и нанести несколько раз сбои в настройке/разрыве параллелизма или сделать структуру среза менее, чем идеальный). Код версии партии, по-видимому, «сгладил» структуру вложенных циклов к моменту ее получения к параллельным вызовам (т. Е. Путем предварительного расчета входных блоков и выполнения вложенных циклов внутри каждого блока), что может объяснять накладные расходы с меньшим параллелизмом. –
Другое дело, что если я понимаю, где вы помещаете 'parfor', пакетная версия перемещает намного меньше данных вокруг: она просто передает параметры' r0', 'rf' и' rn' и промежуточные переменные строятся локально для каждого рабочего, но 'parfor' внутри' int3d_ser' приведет к тому, что подмножества временных переменных, созданных на master, будут упорядочены и отправлены каждому работнику. –
.что произойдет, если вы возьмете функцию 'int3d_batch_cluster' и замените вызовы' createTask' символом 'parfor icore = 1: ncores' вокруг обычного вызова функции' int3d_ser'? Это скажет вам, является ли это механизмом 'parfor' как таковым или как ваш код неявно структурирует партии работ, которые должны быть отправлены рабочим. –