2017-07-11 6 views
1

Beispiel-Code einer Klasse:Mit Bezug auf Klassenmethode in parfor Schleife: signifikante Speichernutzung

classdef testcls 
    methods 
     function sayhello(~) 
      disp('Hello! ') 
     end 
    end 
end 

und jetzt, wenn ich die Methode in parfor wie unten

A = testcls; 
parfor ii = 1:4 
    A.sayhello() 
end 

Mlint sagt mir, eine Performance nennen Ausgabe über die Verwendung von A in der Schleife:

The entire array or structure 'obj' is a broadcast variable. This might result in unnecessary communication overhead.

Und ich kann SUPPR Diese Nachricht mit anonymer Funktion:

Aber meine Frage ist, wird dies helfen mit der Geschwindigkeit in jedem Fall? Gibt es einen besseren Weg, eine Methode in parfor aufzurufen?

Dann wird der Fall komplizierter, wenn ich Eingabe/Ausgabe-Argumente der Funktion einrichten möchte?

classdef testcls 
    methods 
     function [out1,out2] = sayhello(~,n) 
      out1 = (['Hello! ', num2str(n)]); 
      out2 = n; 
     end 
    end 
end 

A = testcls; 
f = @A.sayhello; 
[a,b] = deal(cell(4,1)); 
parfor ii = 1:4 
    [a{ii},b{ii}] = feval(f,ii); 
end 

EDIT:

Ich habe erheblichen Ressourcenverbrauch beobachtet Speicherkopiervorgänge im Zusammenhang. Grundsätzlich erstellt der Job-Dispatcher ein identisches Objekt für jeden Worker, einschließlich aller geänderten Eigenschaften.

Die Verwendung f = @A.sayhello; Verwendung speichert Matlab nicht von Mempy-das gesamte Objekt zu jedem einzelnen Worker, auch wenn die Methode selbst keine Klasseneigenschaft aufruft oder speichert.

Ich denke, das ist der Weg, um Transparenz zu gewährleisten. Wenn jedoch die Datenmenge riesig ist, wird dies zu einem großen Schmerz im Kopf.

Gibt es eine Möglichkeit, anstatt die gewünschte Funktion in einer eigenständigen dateibasierten Funktion zu isolieren, von sayhello in dem Objekt, das das Memcopying des gesamten Objekts nicht aufruft?


EDIT: Dank @gnovice für die suggestive Antwort. Ich habe einen Testfall gemacht, um parfor mit der statischen Methode, parfor mit der nicht statischen Methode und der seriellen Ausführung mit arrayfun zu vergleichen.

Test case 1: parfor mit nicht statischer Methode (Kontrolle)

parfor non-static

Wie in dem Speicherverwendungsdatensatz zu sehen sind, die Schaffung eines einzelnen Objekts testcls verwendet ~ 700 MB RAM, angezeigt durch Label 1, gefolgt von einem clear Befehl mit der Bezeichnung 2, und die parfor Schleife läuft über Label 3. Die maximale Nutzung von parfor ist etwa 4 mal als einzelnes Objekt, während der Pool 4 Arbeiter hat.

Testfall 2: parfor mit statischer Methode

parfor static

Das Testverfahren wird auf die gleiche Weise durchgeführt und etikettiert. Aus diesem Beweis ergibt sich die Schlussfolgerung, dass nur wenn die Methode statisch gemacht wird, verhindert wird, dass der Parpool identische Objekte für alle Arbeiter erzeugt.

Testfall 3: Serien Auswertung arrayfun

serial

Da arrayfun Verwendung führt eine nicht-sequenzielle seriellen Batch-Auswertung, hier ist kein Grund für arrayfun mehr Arbeitsspeicher zu verwenden, als von einem einzigen Thread benötigt. Daher die Beweise.

Beispielcode:

classdef testcls 
    properties 
     D 
    end 
    methods (Static = false) 
     function [out1,out2] = sayhello(~,n) 
      out1 = (['Hello! ', num2str(n)]); 
      out2 = n; 
     end 
    end 
    methods 
     function obj = testcls(~) 
      obj.D = rand(1e8,1); 
     end 
    end 
end 

den Test ausführen zu können, verwenden Sie dieses Skript:

clear;clc;close all 

A = testcls; 
f = @A.sayhello; 
parfor ii = 1:4 
    feval(f,ii) 
end 

Sie können die parfor mit arrayfun für serielle Validierung ersetzen.

+1

Ihr letzter gibt Beispielcode die Fehler: „Der in Scheiben geschnittene Variable f zu einem Funktionsgriff nicht beziehen müssen“ - Sie müssen stattdessen "feval (f, ii)" verwenden ([siehe hier] (https://www.mathworks.com/help/distcomp/objects-and-handles-in-parfor-loops.html)) – whrrgarbl

+0

@ whrrgarbbl whoa du hast recht. Mein eigener Code hatte keinen Streit, aber ich dachte, es könnte mit einem funktionieren. Ich bearbeite meinen Code im einfachsten Fall. – Yvon

Antwort

1

Für Methoden, die keine Eigenschaft der Klasse referenzieren müssen, ist es wahrscheinlich am besten, sie static methods zu machen. Aus der Dokumentation:

Static methods are associated with a class, but not with specific instances of that class. These methods do not require an object of the class as an input argument, unlike ordinary methods which operate on specific objects of the class. You can call static methods without creating an object of the class

Da sie ohne genannt werden kann, ein Objekt dieser Klasse zu erstellen, sollte diese Ihnen helfen, die unnötige Duplizierung des gesamten Objekts über jeden Arbeitnehmer zu vermeiden.

Beispiel Methode:

classdef testcls 
    ... 
    methods(Static) 
    function sayhello 
     disp('Hello!'); 
    end 
    end 
    ... 
end 

Und es von jedem Arbeiter zu nennen:

testcls.sayhello(); 
+0

Vielen Dank für die Idee! Ich habe einen Vergleichstest durchgeführt und die Ergebnisse in der Frage gepostet. Leider eliminieren statische Methoden nicht das identische Objekt-Laichen. Bitte werfen Sie einen Blick auf die Schnappschüsse. – Yvon

+1

@Yvon: Das Aufrufen der statischen Methode mit 'f = @Sayhello;' funktioniert möglicherweise nicht, da es immer noch an ein Objekt "A" gebunden ist. Ich würde die statische Methode erneut testen, indem ich sie ohne ein Objekt aufrufe, nur den Klassennamen: 'f = @ testcls.sayhello;'. Ich würde unterschiedliche Ergebnisse dafür erwarten. – gnovice

+0

Sie haben Recht. Der Aufruf der statischen Methode nach Klassennamen würde das unerwünschte Hervorbringen identischer Objekte verhindern. Es funktioniert auf diese Weise, obwohl ich die Chance verliere, auf klassenweite Laufzeitparameter zuzugreifen, weil ich "Daten" (kommt in großen Mengen) nicht von "Parametern" unterscheiden kann (nur ein paar Zahlen, die das laufende Programm steuern). – Yvon