Ich schreibe MATLAB-Code ein 3-dimensionales Integral auszuführen:Warum ist Batch-Modus so viel schneller als 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
für die zugehörige int3d_par
(parfor) Version, öffne ich einen Matlab-Pool und ersetzen Sie einfach die for
mit einem parfor
. Ich bekomme ziemlich gute Beschleunigung, indem ich es auf mehr Kernen laufe (meine Tests sind von 2 bis 8 Kerne).
Allerdings, wenn ich die gleiche Integration in Batch-Modus mit laufen:
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
merke ich, dass es viel, viel schneller ist. Warum sollte diese Integration im Batch-Modus anders sein als in parfor
?
Als Referenz, ich teste den Code mit N
aus kleinen Zahlen wie 10 und 20 (um die Konstante in der polynomischen Approximation der Laufzeit zu erhalten) zu größeren Zahlen wie 1000 und 2000. Dieser Algorithmus wird kubisch skalieren, da ich die Nummer zuweisen der Integrationsknoten in der theta
und phi
Richtung zu einem konstanten Vielfachen der angegebenen N
sein.
Für 2000 Knoten dauert die parfor
Version etwa 630 Sekunden, während die gleiche Anzahl an Knoten im Batch-Modus etwa 19 Sekunden dauert (wobei etwa 12 Sekunden einfach Overhead-Kommunikation sind, die wir auch für 10 Integrationsknoten erhalten).
Welche 'for' ersetzen Sie mit einem' parfor'? Es könnte einen Unterschied in dieser verschachtelten Schleifenstruktur machen (z. B. das "Parfor" treffen und den Parallelismus-Aufbau/den Teardown-Overhead mehrfach aufwerfen oder eine weniger als ideale Slice-Struktur machen). Der Stapelversionscode scheint die Nested-Loop-Struktur bis zum Erreichen der parallelen Aufrufe "geebnet" zu haben (d. H. Durch Vorberechnung von Eingabe-Chunks und Ausführung der verschachtelten Schleifen in jedem Chunk), was einen geringeren Parallelitäts-Overhead erklären könnte. –
Die andere Sache ist, dass, wenn ich verstehe, wo Sie den "Parfor" setzen, die Batch-Version viel weniger Daten bewegt: Es gibt nur die Parameter "r0", "rf" und "rn" um und Die Zwischenvariablen werden lokal auf jedem Worker erstellt, aber ein "Parfor" in "int3d_ser" würde dazu führen, dass Teilmengen der temporären Variablen, die auf dem Master erstellt wurden, gemarshallt und an jeden Worker gesendet werden. –
Zum BeispielWas passiert, wenn man die 'int3d_batch_cluster' Funktion benutzt und die' createTask' Aufrufe durch 'parfor icore = 1: ncores' um einen normalen Funktionsaufruf zu' int3d_ser' ersetzt? Das würde Ihnen sagen, ob es der "Parfor" -Mechanismus per se ist oder nur, wie Ihr Code implizit die Chargen von Arbeit strukturiert, die an die Arbeiter gesendet werden soll. –