2015-08-19 21 views
12

Ich versuche, ein Stück parallelen Code zu erstellen, um die Verarbeitung eines sehr großen Arrays (einige hundert Millionen Zeilen) zu beschleunigen. Um dies parallel zu machen, zerhackte ich meine Daten in 8 Teile (meine Anzahl an Kernen) und versuchte, jedem Arbeiter 1 Stück zu schicken. Ein Blick auf meine RAM-Nutzung aber es scheint, jedes Stück zu jedem Arbeiter senden wird, effektiv meine RAM-Nutzung von 8. Ein Mindestarbeitsbeispiel multipliziert:Senden von Daten an Worker

A = 1:16; 
for ii = 1:8 
    data{ii} = A(2*ii-1:2*ii); 
end 

Nun, wenn ich diese Daten an Arbeitnehmer parfor es mit schicken scheint

output = cell(1,8); 
parfor ii = 1:8 
    output{ii} = data{ii}; 
end 

I verwenden tatsächlich eine Funktion innerhalb der parfor Schleife, aber dies stellt den Fall dar: die vollständige Zelle statt nur das gewünschte Stück zu senden. Sendet MATLAB tatsächlich die volle Zelle data an jeden Arbeiter, und wenn ja, wie kann man nur das gewünschte Stück senden?

+4

Wenn Ihre Daten ein [geschnitten Variable] ist (http://mathworks.com/help/distcomp/sliced-variables.html) es wird „geschnitten“ und diese Scheiben an die Arbeiter übertragen werden nur werden ; Verwenden Sie aufgeschnittene Variablen in Ihrem echten Code? –

+0

Ich verwende ein Zellenfeld in meinem tatsächlichen Code, wie hier dargestellt. Ich werde in die geschnittene variable Funktion schauen, danke. – Adriaan

+0

Vielleicht manuell schneiden, individuelle Jobs für jedes Stück einreichen: http://de.mathworks.com/help/distcomp/submit.html – Daniel

Antwort

10

In meiner persönlichen Erfahrung fand ich, dass parfeval ist besser in Bezug auf Speicherverbrauch als parfor. Darüber hinaus scheint Ihr Problem eher zerbrechlich zu sein. Sie können daher parfeval verwenden, um kleinere Aufträge an MATLAB-Mitarbeiter zu senden.

Nehmen wir an, Sie haben workerCnt MATLAB Worker, mit denen Sie arbeiten jobCnt Jobs. Sei data ein Zellenarray der Größe jobCnt x 1, und jedes seiner Elemente entspricht einem Dateneingang für die Funktion getOutput, die die Datenanalyse durchführt. Die Ergebnisse werden dann in dem Zellenfeld output der Größe jobCnt x 1 gespeichert.

Im folgenden Code werden Jobs in der ersten for-Schleife zugewiesen und die Ergebnisse werden in der zweiten while-Schleife abgerufen. Die boolesche Variable doneJobs gibt an, welcher Job ausgeführt wurde.

poolObj = parpool(workerCnt); 
jobCnt = length(data); % number of jobs 
output = cell(jobCnt,1); 
for jobNo = 1:jobCnt 
    future(jobNo) = parfeval(poolObj,@getOutput,... 
     nargout('getOutput'),data{jobNo}); 
end 
doneJobs = false(jobCnt,1); 
while ~all(doneJobs) 
    [idx,result] = fetchnext(future); 
    output{idx} = result; 
    doneJobs(idx) = true; 
end 

Auch Sie können diesen Ansatz einen Schritt weiter gehen, wenn Sie mehr Speicher sparen möchten. Sie können nach dem Abrufen der Ergebnisse eines abgeschlossenen Jobs das entsprechende Element future löschen. Der Grund ist, dass dieses Objekt alle Eingabe- und Ausgabedaten der getOutput-Funktion speichert, die wahrscheinlich sehr groß sein wird. Aber Sie müssen vorsichtig sein, wenn Mitglieder von future Ergebnisse index shift löschen.

Das folgende ist der Code, den ich für diesen porpuse schrieb.

poolObj = parpool(workerCnt); 
jobCnt = length(data); % number of jobs 
output = cell(jobCnt,1); 
for jobNo = 1:jobCnt 
    future(jobNo) = parfeval(poolObj,@getOutput,... 
     nargout('getOutput'),data{jobNo}); 
end 
doneJobs = false(jobCnt,1); 
while ~all(doneJobs) 
    [idx,result] = fetchnext(future); 
    furure(idx) = []; % remove the done future object 
    oldIdx = 0; 
    % find the index offset and correct index accordingly 
    while oldIdx ~= idx 
     doneJobsInIdxRange = sum(doneJobs((oldIdx + 1):idx)); 
     oldIdx = idx 
     idx = idx + doneJobsInIdxRange; 
    end 
    output{idx} = result; 
    doneJobs(idx) = true; 
end 
3

Ich würde vorschlagen, den spmd Befehl von MATLAB zu verwenden.

Sie können Code fast so schreiben, wie es für eine nicht parallele Implementierung wäre, und auch Zugriff auf den aktuellen Worker durch die labindex "System" Variable haben.

Werfen Sie einen Blick hier:

http://www.mathworks.com/help/distcomp/spmd.html

Und dies auch über spmd vs parfor SO Frage:

SPMD vs. Parfor

+0

Während die Verwendung von SPMD dem Code helfen kann, wird die Frage eher umgangen als beantwortet. Ich möchte wissen, wie ich meine Daten ohne unnötigen Aufwand an die Mitarbeiter senden kann, damit ich sie auch in anderen Code-Stücken verwenden kann. – Adriaan

+0

Die Verwendung von SPMD oder Parfor spielt in Bezug auf die RAM-Nutzung keine Rolle, aber der Code, der SPMD verwendet, dauert etwa 1,2 mal länger als die Parfor-Implementierung. – Adriaan

+0

Wenn Sie die gleiche Logik wie im Beispiel verwenden, dann haben Sie etwas falsch in Ihrem Code. Da es einen fast Debuggen Ihres Codes erfordern würde, um den tatsächlichen Fehler zu sehen, schlug ich eine schnelle Alternative vor, um Ihr Problem zu lösen. Wenn Sie Parfor benötigen, sollten Sie den gesamten Code posten. – Xxxo

4

Der Kommentar von @ms ist richtig - wenn parforScheiben ein Array, dann wird jeder Worker nur das Slice gesendet, das für das Schleifen-Iteratio notwendig ist ns, an dem gearbeitet wird. Es kann jedoch vorkommen, dass die RAM-Auslastung über das hinausgeht, was Sie ursprünglich erwartet haben, da leider Kopien der Daten erforderlich sind, da sie vom Client an die Worker über den Kommunikationsmechanismus parfor übergeben werden.

Wenn Sie die Daten nur für die Worker benötigen, dann ist es die beste Lösung, wenn möglich nur auf die Worker zu erstellen/laden/zuzugreifen. Es klingt, als ob Sie nach Datenparallelität und nicht nach Aufgabenparallelität streben, für die spmd tatsächlich eine bessere Anpassung ist (wie @Kostas vorschlägt).

+0

Ich bin in der Tat nach Datenparallelität, da ich die gleiche Operation auf alle meine Hunderte von Millionen Zeilen anwenden möchte. Ich kann jedoch meine Daten auf den Arbeitern nicht erstellen, da ich sie zuerst von einer externen Datei laden muss. Diese Daten müssen dann sortiert und in Stücke geschnitten und jedes Stück an einen Arbeiter gesendet werden. Dann, nachdem jeder Worker seine vorgesehene Aufgabe ausgeführt hat, möchte ich das vollständige Array in meinem Client sammeln, um weiter daran zu arbeiten. – Adriaan

+0

Die Datenseiten auf geschnittenen Variablen sind ein wenig kurz für meinen Geschmack, ist es möglich, dass Sie ein kleines Stück Code hinzufügen, der zeigt, wie man eine Variable schneidet? Entweder das Array A oder die Zellendaten sind für ein Beispiel in Ordnung. – Adriaan

Verwandte Themen