Seite 2 von 2
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 09:05
von BastiL
sparrow hat geschrieben: Mittwoch 30. Oktober 2019, 08:51
Dadurch dass aber alle Variablen auch noch global sind, ist das für dich ohnehin schwierig bis unmöglich zu debuggen.
Mit deinem "Beispielcode" hat das hier übrigens gar nichts mehr zu tun. Außer einer Schleife sehe ich nichts was gleich ist. Vor allem nicht die dahinterliegenden Datenstrukturen und Objekte.
Ok, die entsprechende Methode von "ensfile" reiche ich nach. Das sol laber eine Export-Funktion sein, die die Daten schreibt und anschließend werden diese Daten nicht mehr gebraucht.
Letztlich brauche ich die globalen Variablen den ganzen Programmdurchlauf über. Das eigentliche Problem scheint ja "res" zu sein, das ist eine lokale Variable.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 09:08
von sparrow
Nee, "res" ist nicht das Problem. Und das habe ich schon sehr oft hier geschrieben. Du hängst dich an der falschen Sache auf.
Globale Variablen braucht man nie. Funktionen bekommen das, was sie brauchen, als Parameter und geben ein Ergebnis (mittels return) zurück.
Dann kann man Code debuggen.
Natürlich kann man das auch nicht tun und denken, dass man es besser kann. Das führt dann halt unkontrolliertem Verhalten, dem man nicht auf die Spur kommt.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 09:25
von BastiL
Ich bin kein Programmierexperte, deswegen würde ich nie behaupten, dass ich es besser kann. Eher das ich es nicht besser weiss.
Letztlich ist es so, dass der Großteil der Arbeit in diesem Fall im Hauptprogramm in globale Variablen gemacht wird. Die gezeigte Funktion greift auf diese Variablen zu, das ist richtig. Ich könnte die globalen Variablen aus dem Hauptprogramm auch an die Funktion übergeben, die Frage ist nur was das hier ändern würde?
Grundsätzlich ist das Programm historisch gewachsen, gleiches gilt für die globalen Variablen. Damit bin ich seit geraumer Zeit selbst nicht mehr zufrieden, deshalb wäre das vielleicht ein guter Zeitpunkt für eine grundsätzliche Überarbeitung der Datenstruktur. Hier freue ich mich über Vorschläge, wie ich so etwas grundsätzlich konzipiere.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 09:34
von __blackjack__
@BastiL: Anmerkungen: Der `list`-Aufruf ist überflüssig, im Grunde auch der `keys()`-Aufruf.
Bei den Namen sind Abkürzungen und fehlende Unterstriche zwischen Worten.
Die Entscheidung welche Methode zum Schreiben verwendet wird kann man vor die Schleife ziehen.
Das Schleifenergebnis lässt sich wie schon früher angedeutet als „comprehension“ schreiben.
Die Funktion würde dann so aussehen:
Code: Alles auswählen
def write_results(
node_scalars,
node_ids,
t16_file,
node_ids_mentat,
write_ascii,
ens_file,
comp_nodes,
):
if write_ascii:
write = ens_file.write_scalar_node_variable_time_step
else:
write = ens_file.write_scalar_node_var_bina_time_step
for i, node_scalar in enumerate(node_scalars):
node_id_to_result = {
node_id: t16_file.node_scalar(node_ids_mentat[node_id], i)
for node_id in node_ids
}
write(node_scalar, node_id_to_result, t16_file.increment, comp_nodes)
Globale Variablen braucht man nicht. Die einfachste und sinnvollste Art Programmiersprachen mit automatischer Speicherverwaltung dabei zu helfen sind ordentliche Funktionen zu schreiben — also keine globalen Variablen zu verwenden.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 09:54
von BastiL
Blackjack: Ok, die Funktion werde ich so umsetzen und berichten wie sich der Speicherbedarf damit entwickelt. Leuchtet mir alles ein. Einzig mit comprehensions stehe ich auf Kriegsfuss, weil ich den Code nicht so gut lesbar und verständlich finde. Welchen Vorteil bietet die comprehension hier?
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 10:44
von __blackjack__
@BastiL: Naja, ein Vorteil von der „comprehension“-Syntax ist das er lesbarer und verständlicher ist. Man sieht sofort das der Zweck ist ein Wörterbuch zu erstellen, und nichts anderes. Und man hat dafür einen eigenen Namensraum, das heisst auch einen Namen ausserhalb des Ausdrucks weniger. `node_id` existiert nur in dem Ausdruck. Etwas effizienter ist es auch.
Am Speicherverbrauch dürfte das nichts ändern, denn es ist unwahrscheinlich das diese Funktion letztlich die entscheidende Stelle ist. Falls es `res` ist, dann wird der Speicher zwar in dieser Funktion belegt, aber in der Funktion selbst sehe ich keinen Grund warum der Speicher nicht auch wieder freigegeben wird. Das kann eigentlich nur passieren wenn die von dort aufgerufene(n) Schreibfunktion(en) Referenzen aufhebt.
Edit: `t16_file.node_scalar()` könnte übrigens auch der Übeltäter sein falls da Daten in dem Speicher geladen werden die dort vorher nicht waren und die dann aber nicht wieder freigegeben sondern beispielsweise gecached werden.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 10:45
von Sirius3
Jetzt ergibt sich doch ein viel klareres Bild. Du hast also gar keinen Indexzugriff auf `results` sondern rufst eine Funktion auf.
Sowohl `list` als auch `keys` sind bei `list(node_ids.keys()):` überflüssig.
Das `del` hat wie schon geschrieben, keinen Einfluß und kann weg, ebenso das `collect`.
Die Funktion hat zu wenig Argumente und zu viele globale Variablen.
Um das Problem mal klarer zu haben:
Code: Alles auswählen
def write_results(nodescalars, node_ids_mentat, node_ids, t16file, ensfile, write_ascii, nscalar, compnodes):
write = ensfile.write_scalar_node_variable_time_step if write_ascii else ensfile.write_scalar_node_var_bina_time_step
for i, nscalar in enumerate(nodescalars):
res = {
node_id: t16file.node_scalar(node_ids_mentat[node_id], i)
for node_id in node_ids
}
write(nscalar, res, t16file.increment, compnodes)
Nun gibt es zwei Stellen, wo Speicher angehäuft werden könnten:
`t16file.node_scalar` oder `ensfile.write_scalar_node_variable_time_step`. Um das zu testen, kannst Du einfach nur node_scalar aufrufen:
Code: Alles auswählen
def write_results(nodescalars, node_ids_mentat, node_ids, t16file, ensfile, write_ascii, nscalar, compnodes):
for i, nscalar in enumerate(nodescalars):
for node_id in node_ids:
t16file.node_scalar(node_ids_mentat[node_id], i)
Wenn das den Speicher füllt, würde das bedeuten, dass dieses t16file nur bei Bedarf geladen wird und da Du mit der Zeit das ganze File brauchst, landet das mit der Zeit auch komplett im Speicher. Lösung wäre, das File bei jedem Loop neu zu öffnen und danach wieder zu schließen.
Liegt der Speicherverbrauch beim Speichern, dann mußt Du irgendwie dafür sorgen, dass die Daten tatsächlich geschrieben werden und nicht im Speicher bleiben. Da ich aber zu diesem ensfile keine Dokumentation gefunden habe, kann ich da nicht weiterhelfen.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 16:09
von BastiL
Sirius3 hat geschrieben: Mittwoch 30. Oktober 2019, 10:45
Nun gibt es zwei Stellen, wo Speicher angehäuft werden könnten:
`t16file.node_scalar` oder `ensfile.write_scalar_node_variable_time_step`.
Wenn das den Speicher füllt, würde das bedeuten, dass dieses t16file nur bei Bedarf geladen wird und da Du mit der Zeit das ganze File brauchst, landet das mit der Zeit auch komplett im Speicher. Lösung wäre, das File bei jedem Loop neu zu öffnen und danach wieder zu schließen.
Auf "t16file.nodescalar" ist mein Verdacht schon früh gefallen. Ich habe das damals durch Schließen und wieder Öffnen des FIles im Speicher getestet - ohne Erfolg. Bleibt wohl ensfile.write_scalar_node_variable_time_step:
Code: Alles auswählen
def write_scalar_node_variable_time_step(self, var_name, variable, time, parts):
self.__scalar_var_file = open(self.directory + var_name + '%03i.scl'%time, 'w')
self.__scalar_var_files.append(self.__scalar_var_file)
print('time =', time, file=self.__scalar_var_file)
for PartID in list(parts.keys()):
print('part', file=self.__scalar_var_file)
print('%10i'%PartID, file=self.__scalar_var_file)
print('coordinates', file=self.__scalar_var_file)
for node in sorted(parts[PartID]):
print('%12.5f'%variable[node], file=self.__scalar_var_file)
self.__scalar_var_file.close()
return
Danke für euere Verbesserungsvorschläge für die Funktion, ich bin gerade dabei das umzusetzen.
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 16:49
von Sirius3
Pfade stückelt man nicht mit + zusammen. Es macht auch selten Sinn, Fileobjekte als Attribut oder in Listen zu speichern, vor allem hier, wo Du das Fileobjekt am Ende der Funktion wieder schließt. Doppelte Unterstriche sind nur in Ausnahmefällen sinnvoll.
So wie es aussieht, hast Du ja dieses `write` selbst geschrieben, daran kann also der Speicherverbrauch nicht liegen. Wie hast Du denn t16file geöffnet und wieder geschlossen?
Code: Alles auswählen
def write_scalar_node_variable_time_step(self, var_name, variable, time, parts):
with open(os.path.join(self.directory, '%s%03i.scl' % (var_name, time), 'w', encoding='ascii') as output:
print('time =', time, file=output)
for part_id, nodes in parts.items():
print('part', file=output)
print('%10i' % part_id, file=output)
print('coordinates', file=output)
for node in sorted(nodes):
print('%12.5f' % variable[node], file=output)
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 16:55
von BastiL
Sirius3 hat geschrieben: Mittwoch 30. Oktober 2019, 16:49
So wie es aussieht, hast Du ja dieses `write` selbst geschrieben, daran kann also der Speicherverbrauch nicht liegen. Wie hast Du denn t16file geöffnet und wieder geschlossen?
Ja ist selbst geschrieben basierend auf einer open source Bibliothek.
Für das Öffnen und Schließen des t16file sieht die Dokumentation der Schnittstelle jeweils genau eine Möglichkeit vor:
Code: Alles auswählen
t16file = py_post.post_open("Filename")
t16file.close()
Re: Stetig steigender Hauptspeicherbedarf
Verfasst: Mittwoch 30. Oktober 2019, 19:11
von Sirius3
Und wie hast Du die beiden Zeilen eingebaut?