Sto scrivendo il codice MATLAB per eseguire un integrale dimensionale 3:Perché la modalità batch è molto più veloce di 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
per la versione associata int3d_par
(parfor), apro una piscina MATLAB e basta sostituire il for
con un parfor
. Ottengo una velocità decente con l'esecuzione su più core (i miei test vanno da 2 a 8 core).
Tuttavia, quando si esegue la stessa integrazione in modalità batch con:
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
mi accorgo che è molto, molto più veloce. Perché fare questa integrazione in modalità batch è diverso rispetto a farlo in parfor
?
Per riferimento, ho testare il codice con N
da piccoli numeri come 10 e 20 (vedere la costante nella approssimazione polinomiale di esecuzione) a numeri più grandi come 1000 e 2000. Questo algoritmo scalare cubicly poiché assegno il numero dei nodi di integrazione nella direzione theta
e phi
per essere un multiplo costante di N
specificato.
Per i nodi 2000, la versione parfor
impiega circa 630 secondi, mentre lo stesso numero di nodi in modalità batch impiega circa 19 secondi (dove circa 12 secondi è semplicemente una comunicazione dall'alto che si ottiene anche per 10 nodi di integrazione).
Quale 'for' stai sostituendo con un' parfor'? Potrebbe fare una differenza in quella struttura ad anello annidato (ad esempio colpendo il 'parfor' e incorrendo più volte nell'overhead di setup/demolizione del parallelismo, o facendo una struttura di slice non proprio ideale). Il codice della versione batch sembra avere "appiattito" la struttura del ciclo nidificato al momento in cui raggiunge le chiamate parallele (cioè, precalcolando i blocchi di input e facendo i cicli nidificati all'interno di ciascun blocco), che potrebbero spiegare il sovraccarico del parallelismo inferiore. –
L'altra cosa è che, se capisco dove stai mettendo il 'parfor', la versione batch sta spostando molti meno dati attorno: passa solo i parametri' r0', 'rf' e' rn' le variabili intermedie vengono costruite localmente su ciascun worker, ma un 'parfor' all'interno di 'int3d_ser' causerebbe il marshalling di sottoinsiemi delle variabili temporanee create sul master e inviate a ciascun worker. –
Es.cosa succede se si prende la funzione 'int3d_batch_cluster' e si sostituiscono le chiamate' createTask' con 'parfor icore = 1: ncores' attorno ad una normale chiamata di funzione a' int3d_ser'? Questo ti dirà se è il meccanismo "parfor" di per sé, o semplicemente come il tuo codice sta strutturando implicitamente i lotti di lavoro da inviare ai lavoratori. –