Verfasst am: 06.02.2015, 17:15
Titel: 'eval' in 'parfor'-Schleife umgehen
Guten Tag zusammen,
in nachfolgendem Code habe ich aus einer for-Schleife eine parfor-Schleife gemacht, um meine Anwendung schneller zu machen. Dabei gab es schon so manchen Stolperstein, jetzt komme ich aber gerade nicht allein weiter.
x=load(filenames(i_files).name,'allg_fahrumgebung','allg_fahrstil');
m=x.allg_fahrumgebung;
n=x.allg_fahrstil;
index_fahrumgebung=find(m==true);
index_fahrstil=find(n==true);
ifisempty(index_fahrumgebung)
index_fahrumgebung=5;
end ifisempty(index_fahrstil)
index_fahrstil=4;
end for i_signal=1:length(signalnames) for i_vars=1:length(varname) load(filenames(i_files).name, varname{i_vars});%Nur selektierte Signale laden
signalnames_temp{i_signal,1}=varname{i_vars};
if ~exist(['allg_t' varname{i_vars}(end-1:end)],'var') load(filenames(i_files).name,['allg_t' varname{i_vars}(end-1:end)]);
signalnames_temp{anz_sig,1}=['allg_t' varname{i_vars}(end-1:end)];
signal_temp(anz_sig,1)={eval(['allg_t' varname{i_vars}(end-1:end)])};
anz_sig=anz_sig-1;
end
%Cell-Array mit allen Signalen
signal_temp(i_signal,1)={eval(varname{i_vars})};
break end end end
.
.
.
clear(signalnames_temp{:}) clear signal_temp
end
Ich möchte die beiden 'eval' umgehen, die noch im Code stehen.
Meine bisherige Forensuche bei GoMatlab war wenig erfolgreich.
Es gab einmal Vorschläge hinsichtlich cell2struct oder ähnlichem, um eval zu umgehen, aber ich habe aber noch keine Lösung gefunden.
Habt ihr vielleicht eine Idee oder eigene Erfahrungen gemacht?
die evals resultieren wohl daraus, dass Informationen in den Variablennamen "versteckt" sind. Das ist keine gute Idee.
Genauso, wie du es zuvor schon gemacht hast, würde ich die Daten aus der .mat-Datei in eine Struktur laden. Dann ist die Indizierung einfacher:
Ich habe eine Version mit for, da läuft auch alles.
Dauert aber teilweise extrem lange, daher jetzt die Idee auf parfor umzustellen.
Sieht das ganze denn anders aus wenn ich mit parfor nur eine gewisse Funktion aufrufen würde, in der ich dann quasi alles mögliche abhandel?
Aber das birgt vermutlich neue Schwierigkeiten ...
ich habe jetzt etwas rum gebastelt und die zeitintensiven Stellen in der Anwendung ausfindig gemacht.
Die eine ist eben jener Speichervorgang, den ich nun mithilfe von parfor schneller abhandeln will.
Hier mein Code Stand jetzt, und der funktioniert soweit auch:
Code:
.
.
parfor i_sichern=1:length(NAMES)
final=auswahl.(NAMES{i_sichern});
savefunc(final,i_sichern);
end
.
.
function savefunc(final,i_sichern)
zusatz=i_sichern;
save(['final' num2str(zusatz)], '-v7.3');
end
Das Problem: nun dauert es wesentlich (!) länger als vorher.
Das liegt wohl daran, dass ich eben nicht vor der PARFOR Schleife den Input "slice", wie MATLAB es ausdrückt, sonder dass "auswahl" immer komplett an jeden einzelnen Worker übergeben wird.
Bist du auch der Meinung, dass dies das Problem ist, oder siehst du noch ein weiteres?
Ich möchte mit der PARFOR Schleife "auswahl" komplett abspeichern, aber nach Fahrzeugen getrennt, genau so wie es jetzt auch passiert.
Weißt du wie ich es schaffe, dass PARFOR jedem Worker von vornherein nur "seinen slice" übergibt, um dann diesen gesondert abzuspeichern?
Dazu sei gesagt, dass die Anzahl an "slices" variabel ist, je nachdem wieviele Fahrzeuge es gibt!
eine Möglichkeit dürfte sein, die Struktur in ein Cell Array umzuwandeln und in dieses zu indizieren.
Läuft der Code lokal auf einem Rechner? Dann sehe ich das Hauptproblem woanders: das Hauptproblem ist ja nicht die Rechenarbeit, sondern das Schreiben von Dateien. Du magst mehrere Kerne beschäftigen, hast ja aber immer noch "nur" eine Festplatte, und auf die wollen nun mehrere Prozesse gleichzeitig zugreifen.
Es wäre bei sowas immer hilfreich, wenn man ein reproduzierbares Beispiel (gerne mit Phantasiedaten, aber die Dimensionen der Daten sollten in vergleichbaren Größenordnungen sein) hätte.
Haralds Kommentar trifft den Punkt: Hier ist wahrscheinlich die Festplatte der begrenzende Faktor und mehrere Kerne gleichzeitig per SAVE speichern zu lassen wird das Problem wahrscheinlich eher vergrößern, denn dann muss der Schreib-Lese-Kopf ja noch öfter hin und her springen.
Was bei SAVE LAufzeit bringen kann ist die Kompression abzuschalten, indem man z.B. das v6-Format wählt. Lies mal unter "doc save" nach.
zuerst einmal vielen Dank für die Antworten. Das ist eine schöne Sache.
Ich habe die besagte Structure nun in ein cell array umgewandelt und als solches versucht mit parfor abzuspeichern.
Das ändert aber soweit erstmal nichts. Also habe ich das entweder nicht so gemacht, wie du es meintest oder aber das Problem liegt halt, wie von dir angeführt, am Schreiben der Dateien.
Was kann man da denn machen?
Mit ist heute zudem aufgefallen, dass die Performance der Anwendung [z.B. in MB/s] scheinbar direkt abhängig von der Größe der zu speichernden Daten im Workspace ist.
Bei kleinerer zu speichernder Datenmenge (~1 GB) läuft die Anwendung sehr flüssig und man denkt, man hat die Lösung gefunden. Da funktioniert alles genau wie ich das möchte. Aber sobald die Speichermenge eine kritische Grenze erreicht (irgendwo oberhalb einem Gigabyte) stellt MATLAB fast die Arbeit ein. Der gesamte Desktop ist phasenweise eingefroren, der Task Manager zeit allerdings die meiste Zeit lediglich eine CPU-Auslastung von 1% an. Der Arbeitsspeicher (16 GB vorhanden) hingegen ist durchweg gut bis sehr gut ausgelastet.
Nun habe ich - wie im unten angehängten Code - vor dem Speichern der Daten alle größeren, nicht mehr gebrauchten Dateien aus dem workspace entfernt. Leider ändert das nichts.
Beispiel:
Ich speichere Dateien für zwei Fahrzeuge ab, wobei der eine "Datenwürfel" am Ende ~700 MB groß ist, der andere lediglich <100 MB.
Insgesamt also <1 GB. Das geht ruck zuck.
Wenn ich nun noch einmal zwei Fahrzeuge wähle, jenes mit 700 MB und ein weiteres von dem ich weiß dass es ähnlich groß ist, dauert allein die erste Speicherschleife um ein vielfaches länger als vorher, obwohl der Output (der ersten Schleife) genauso groß ist.
Daher müssen die Einbuße in der Performance meiner Meinung nach irgendwie auch schon von der "insgesamt beabsichtigten Menge" der zu speichernden Daten abhängen.
Kurz zu meiner Anwendung:
Es wird mithilfe MetaDaten eine GUI aufgebaut, in der der Nutzer nach diversen Kriterien aus einem Stamm von Daten eine Selektion vornehmen kann. Der für mich interessante Teil beginnt nun, wenn der Nutzer "Datenwürfel erzeugen" klickt und MATLAb die Info der vorgenommenen Selektion erhält:..............
Code:
GUI=guihandles(h.Fig);
%Ausgewählte Signale und Fahrzeuge an Würfelfunktion suchen und übergeben
c=1;
selected_channels=get(GUI.listbox_channels_selected,'String');
selected_fzgnames_string=get(GUI.listbox_fzgnames,'String');
selected_fzgnames_value=get(GUI.listbox_fzgnames,'Value');
for i_fzgnames=1:length(selected_fzgnames_string) if i_fzgnames == selected_fzgnames_value(c)
selected_fzgnames{c,1}=selected_fzgnames_string{i_fzgnames,1};
iflength(selected_fzgnames_value)==c
break else
c=c+1;
end end end set(GUI.static_fehler,'String','Passende Daten werden gesucht...');
Figobj=findobj('-property','Enable');
set(Figobj,'Enable','off');
%Infos über Fahrstil und Fahrumgebung suchen und übergeben
fahrumgebung=[get(GUI.checkbox_fahrumgebung_stadt,'Value'),get(GUI.checkbox_fahrumgebung_land,'Value'),get(GUI.checkbox_fahrumgebung_autobahn,'Value'),get(GUI.checkbox_fahrumgebung_berg,'Value')];
fahrstil=[get(GUI.checkbox_fahrstil_schonend,'Value'),get(GUI.checkbox_fahrstil_durchschnitt,'Value'),get(GUI.checkbox_fahrstil_sport,'Value')];
for anz_kamp=1:length(selected_fzgnames)
%Kampagnennamen aus Fahrzeugnamen extrahieren
unterstrich=strfind(selected_fzgnames{anz_kamp,1},'_');
kampagnenname{anz_kamp,1}=selected_fzgnames{anz_kamp,1}(unterstrich(end-1)+1:unterstrich(end)-1);
end
for i_kampagnen=1:length(selected_fzgnames)
NAMES = fieldnames(wuerfel.(['Kampagne_' kampagnenname{i_kampagnen}]));
auswahl.(NAMES{i_kampagnen})=wuerfel.(['Kampagne_' kampagnenname{i_kampagnen}]).(NAMES{i_kampagnen});
end
for i_NAMES=1:length(NAMES)
final=struct2cell(auswahl.(NAMES{i_NAMES}));
%dateien=fieldnames(final{i_NAMES});
anz_dateien=length(final);
parfor i_sichern=1:anz_dateien
wuerfelchen=final{i_sichern};
savefunc(wuerfelchen,i_sichern,i_NAMES,NAMES);
end end
function savefunc(wuerfelchen,i_sichern,i_NAMES,NAMES)
dirpath=pwd;
zusatz=i_sichern;
if ~exist([dirpath '\Datenwuerfel\' NAMES{i_NAMES,1}]) mkdir([dirpath '\Datenwuerfel\'], NAMES{i_NAMES,1});
addpath([dirpath '\Datenwuerfel\' NAMES{i_NAMES,1}]);
end save([dirpath '\Datenwuerfel\' NAMES{i_NAMES,1} '\wuerfelchen' num2str(zusatz) '.mat'],'wuerfelchen','-v7.3');
end
[wuerfel] = datenwuerfel lädt dabei die passenden Dateien in den Workspace und ruft dazu wiederum eine weitere Funktion auf.
Das ist sehr umfangreich, daher hoffe ich dass der Codeausschnitt reicht.
Wo brauche ich nun konkret Antworten:
-habe ich die Umstellung von structure zu cell array so gemacht, wie du es meintest?
-Warum ist meine CPU-Auslastung während der parfor-Schleife fast die gesamte Zeit bei ~1%?
-Macht es Sinn, vor der parfor Schleife gewisse Teile des Workspace zu "clearen"?
-Wie habe ich diese Unterschiede hinsichtlich der Performance zu verstehen? Bei kleinen Dateien geht es fix, bei (mehreren) größeren Dateien geht die Anwendung in die Knie. (Das gilt übrigens auch für die funktionierende Version mit for statt parfor. Auch hier nimmt die Performance spürbar ab, jedoch erst bei einem Gesamtoutput ~2,5 GB)
leider hilt die Umstellung auf v6 auch nur bei verhältnismäßig kleinen Datenwürfeln (komprimiert <1 GB).
Offensichtlich kann Matlab kleinere Datenpakete sehr viel besser handhaben (in MB/s) als größere. Zeitmessungen haben bei mir ergeben, dass die Geschwindkeit ab einer gewissen Datengrößer deutlich einbricht.
Nun frage ich mich: Kann man so etwas wie einen "Datenbegrenzer" oder "Datenbremse" einbauen? Also dass die Anwendung bei einer bestimtmen Größe an eingelesenen Daten das Einlesen weiterer Daten vorerst stoppt, mit dem eingelesenen Datenpaket weiterarbeitet und wenn er damit fertig ist, sich das nächste Paket lädt?
In meiner Anwendung gehe ich jetzt bereits einen Schritt in diese Richtung in dem ich nun gar keinen Datenwürfel mehr erzeuge, sondern ich speichere die nach bestimmten Kriterien ausgewählten und dann eingelesenen Daten direkt separat wieder ab. Gesondert nach Fahrzeugen.
Das Problem: Der Nutzer kann neben einigen anderen Kriterien nach Fahrzeugen und nach Signalen eine Auswahl treffen. Da ich nun separat nach Fahrzeugen abspeichere, läuft die Anwendung auch bei sehr großen Datenwürfeln (~10 GB) ziemlich flüssig, solange die vorgenommenen Auswahl zwar viele Fahrzeuge, aber jeweils nur einige wenige Signale betrifft.
Andersrum geht Matlab bei nur einigen wenigen Fahrzeugen und dafür vielen Signalen wieder in die Knie.
Meine Fragen:
-gibt es so etwas wie einen "Datenbegrenzer" oder ein Erkennen von Dateigrößen in matlab, dass hierbei hilfreich sein könnte um die Datenpakete klein zu halten?
-Macht es vielleicht Sinn, insgesamt eher nach Signalen zu speichern als Fahrzeuge, oder dreht das das Problem nur um?
kommen die Daten denn wirklich aus MATLAB oder eventuell aus Simulink?
Insbesondere bei kommerziellen Anwendungen würde ich da auch mal direkt MathWorks kontaktieren.
Grüße,
Harald
Einstellungen und Berechtigungen
Du kannst Beiträge in dieses Forum schreiben. Du kannst auf Beiträge in diesem Forum antworten. Du kannst deine Beiträge in diesem Forum nicht bearbeiten. Du kannst deine Beiträge in diesem Forum nicht löschen. Du kannst an Umfragen in diesem Forum nicht mitmachen. Du kannst Dateien in diesem Forum posten Du kannst Dateien in diesem Forum herunterladen
MATLAB, Simulink, Stateflow, Handle Graphics, Real-Time Workshop, SimBiology, SimHydraulics, SimEvents, and xPC TargetBox are registered trademarks and The MathWorks, the L-shaped membrane logo, and Embedded MATLAB are trademarks of The MathWorks, Inc.