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