2015-04-17 6 views
8

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).

+2

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. –

+1

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. –

+0

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. –

Antwort

1

Nach dem Sprechen mit Mathworks Unterstützung, es scheint, ich hatte ein grundlegendes Missverständnis, wie parfor funktioniert. Ich hatte den Eindruck, dass parfor wie openMP gehandelt, während Batch-Modus wie mpi in Bezug auf gemeinsame vs verteilten Speicher handelte.

Es stellt sich heraus, dass parfor tatsächlich auch verteilten Speicher verwendet. Wenn ich zum Beispiel 4 Batch-Funktionen erstelle, passiert der Overhead für die Erstellung eines neuen Prozesses viermal. Ich dachte, dass die Verwendung einer parfor verursachen würde, dass Overhead nur einmal passieren würde und dass die parfor würde dann im selben Speicherplatz stattfinden. Das ist nicht der Fall.

In meinem Beispiel Code stellt sich heraus, dass ich für jede Iteration der parfor tatsächlich den Overhead des Erstellens eines neuen Threads nehme. Wenn ich "Äpfel mit Äpfeln" vergleiche, sollte ich wirklich die gleiche Anzahl von Stapelaufrufen erstellen wie Iterationen in der Schleife parfor. Dies ist der Grund, warum die parfor Funktion so viel länger dauerte - ich war gezwungen, mehr Overhead für multiprocessing viel.

+0

Bedeutet dies, dass der Batch-Modus schneller als Parfor ist? –

Verwandte Themen