Zipfile, Lzma und Memory Error

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
Antworten
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,

hab folgendes Testprogram:

Code: Alles auswählen

import zipfile
import itertools


def main():
	with zipfile.ZipFile("test.zip", mode='w', compression=zipfile.ZIP_LZMA) as file_zip:
		for x in itertools.count():
			b = str(x)
			print(b)
			file_zip.writestr(b, b)
if __name__ == "__main__":
	main()
Betrachte ich nun den Speicherverbrauch meines Programmes sehe ich, dass er zuerst stark ansteigt, wieder fällt, ansteigt und fällt usw.
MMn. liegt das daran, dass die writes gebuffert werden. Soweit so gut.
Leider fällt der Speicherbedarf aber nicht auf den initalien Wert ab sondern wächst mit der Zeit mit.

Das heißt, dass dieses Programm nach einer gewissen Zeit meinen gesamten Ram benötigt und deshalb mit einem Memory Error beendet wird.

Meine Frage ist nun: Wie verhindere ich das? Ich hätte erwartet, dass es einen konstanten Buffer für das schreiben gibt und nicht, dass anscheinend auch teile des Gezippten irgendwo im Ram weite rumliegen.

MfG.


p90
Zuletzt geändert von p90 am Dienstag 20. Januar 2015, 14:07, insgesamt 1-mal geändert.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@p90: Bei zip-Files stehen alle Dateiinformationen am Ende der Datei, können also erst geschrieben werden, wenn die ZIP-Datei geschlossen wird, müssen demnach im Speicher bleiben. Bei Deinen vielen tausenden Files kann das ganz schön Speicher kosten.
BlackJack

@p90: Als erstes müsste man mal herausfinden wofür der Speicher tatsächlich verbraucht wird.

Was hier auf jeden Fall ansteigt ist das ”Inhaltsverzeichnis” der ZIP-Datei. Die muss so lange im Speicher gehalten werden bis die Datei geschlossen wird, denn das Inhaltsverzeichnis wird in ZIP-Dateien als letztes in die Datei geschrieben. Wie viele Dateien hast Du denn archiviert bevor es kracht? Ist das überhaupt ein realistisches Szenario welches Du da gebastelt hast? Bei so kurzen Dateiinhalten macht LZMA keinen Sinn. Wahrscheinlich nicht einmal DEFLATE.
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,


das oben is tnatürlich nur ein Minimalbeispiel um das Problem zu zeigen.
Hatte bei einer meiner Messungen genau diesen Fehler und versuche nun diesen zu verhindern. Also den Crash hatte ich sobald die kompimierte Datei bei 6GB lag.
Das dürften grob 60GB Messdaten sein (hab ca. 90% Komprimierung, deshalb nehme ich das LZMA) und ca. 5 Millionen Dateien.

Das mit dem Inhalsverzeichnis macht Sinn auch wenn es natrülich doof ist. MWn. ist das Verzeichnis am Ende der Datei aber nicht Notwendig (zumindest kann ich mit
unzip -FF Ziparchive reparieren, bei denen das Ende fehlt.) sondern nur für den schnellen Zugriff auf Dateien benötigt.

Hm, was nehme ich den dann am besten? Einfach eine Datei, erst alles reinschmeißen und dann vor dem Transport zum Cluster komprimieren?
Oder habt ihr eine andere Idee?
BlackJack

@p90: Wenn Du keinen schnellen Zugriff auf archivierte Einzeldateien benötigst würde ich ein TAR-Archiv erstellen und das (on-the-fly) mit LZMA komprimieren.

Was sind denn das für Daten? Bei den Kompressionsraten klingt das ja fast nach Text. Wäre es denn möglich das ein wenig strukturierter zu Speichern zum Beispiel in einer oder mehreren HDF5-Dateien, binär, und da vielleicht auch schon komprimiert?
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

BlackJack hat geschrieben:@p90: Wenn Du keinen schnellen Zugriff auf archivierte Einzeldateien benötigst würde ich ein TAR-Archiv erstellen und das (on-the-fly) mit LZMA komprimieren.
Das ginge wenn tar diese Problem nicht hat. Werde es gleich mal vorbereiten und dann versuchen. Danke für den Tipp!
BlackJack hat geschrieben: Was sind denn das für Daten? Bei den Kompressionsraten klingt das ja fast nach Text. Wäre es denn möglich das ein wenig strukturierter zu Speichern zum Beispiel in einer oder mehreren HDF5-Dateien, binär, und da vielleicht auch schon komprimiert?
Letztendlich sind es Messdaten von einem Oszilloscope die ich als String bekomme (also alla 0, 0.1, 0,2).
Ich könnte diese auch strukturierter Speichern, darf das aber nicht weil ich von "oben" ein "Dann kann das ja keiner mehr lesen" bekomme ;)
Bin halt als Student nicht ganz frei wie ich die Daten speichere weil man Angst hat, dass der nächte dann nicht weiß wie er damit umzugehen hat.
BlackJack

@p90: Dann solltest Du Dich bei Gelegenheit mal mit HDF5 beschäftigen. Da kann man zum einen effizient und platzsparend mehrdimensionale Werte Arrays drin speichern, die innerhalb der Datei in einer Art Verzeichnishierarchie organisieren und auch Metdadaten zum Beispiel als Key/Value-Paare zu den einzelnen Datenobjekten speichern. Also zum Beispiel so etwas wie Gerät, Aufzeichnungsdatum/-zeitraum, Geräteeinstellungen, und so weiter. Das kann man frei festlegen was man da speichert. Was man eben so braucht damit man selbst, oder andere, die Daten später mal wieder lesen wollen. Es gibt auch generischer Viewer wie hdfview (Java) mit dem man sich so etwas anschauen kann, und Tools um Daten als CSV zu exportieren.

HDF wurde ursprünglich mal von der NASA angeschoben, weil die etwas brauchten um grössere Messdatenmengen so zu speichern dass sie in x Jahren noch wissen was das mal war. Wird mittlerweile zumindest im wissenschaftlichen Umfeld oft genutzt. Ich bin damit zum Beispiel im Studium in der Meteorologie in Kontakt gekommen.
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

Hi,

danke für den Tip, werde es mir mal privat anschauen aber hier auf der Uni habe ich damit vermutlich keine Chance ^^.
Mache eigentlich Teilchenphysik und da wird dann alles mit ROOT vom Cern gemacht was natrülich wieder sein eigenes Datenformat mitbringt und
natürlich keine vernünftige Anbindung an Python oder ähnliches hat.

[EDIT]

Mist, ich befürchte, tarfile löst mein Problem nicht.

Hie rnochmal mein TestProgramm mit Tarfile:

Code: Alles auswählen

import tarfile
import io

import itertools


def string2tar(name, string):
	string = string.encode('ascii')
	tmpfile = io.BytesIO(string)
	tarinfo = tarfile.TarInfo(name=name)
	tarinfo.size=len(string)#len AFTER encoding!!!
	return (tarinfo, tmpfile)

def main():
	with tarfile.open("test.zip", "w|xz") as file_zip: #passiert auch mit w:xz
		for x in itertools.count():
			b = str(x)
			print(b)
			file_zip.addfile(*string2tar(b,b))

if __name__ == "__main__":
	main()
(tarfile hat keine entsprechung von zipfile.writestr deshalb der Kram mit io.BytesIO() )

Lasse ich das Programm laufen schießt es sofort auf 100MB Ram hoch um dann langsam immer weiter zu klettern.
Sieht jetzt nicht ganz so arg schlimm aus wie bei zipfile aber es ist noch da.

[EDIT2]
Ah ich glaub ich habs.

Damit man durch das tarfile kein Memory Leaked muss man periodisch sowas amchen:

Code: Alles auswählen

file_zip.members = []
file_zip.offset = 0
Das wäre natürlich eine doofe Idee wenn man das Tarfile im selben Prozess nochmal lesen möchte, ich möchte aber nur schreiben ergo ist das okay, denke ich.
Sirius3
User
Beiträge: 17711
Registriert: Sonntag 21. Oktober 2012, 17:20

@p90: würde mich wundern, wenn bei Euch niemand HDF5 benutzen würde. Das ist auch das Format das Matlab für seine .mat-Files verwendet und Matlab ist ja auch im universitären Bereich nicht tot zu kriegen.
BlackJack

@p90: Ich weiss es ist nur ein Testprogrämmchen, aber eine LZMA komprimierte Tar-Datei ``test.zip`` und als Variablenname `zip_file` zu verwenden ist IMHO sehr irreführend. ;-)
p90
User
Beiträge: 198
Registriert: Donnerstag 22. Juli 2010, 17:30

@Blackjack:

Danke, hab den Fehler korrigiert (also bei mir hier), sollte natürlich tar.xz sein.

@Sirius3
Zumindest kennt hier keiner HDF5 und wenn ich mir so die ROOT mailingliste so angucke scheint es da gewisse Animositäten zwischen den ROOT Machern und HDF5 zu geben ^^
Aber das liegt vermutlich daran, dass wir Teilchen- und Beschleunigerphysik machen, aus der Astroteilchenphysik gibt es anscheinen immer wieder Anfragen ob man nicht auch HDF5 unterstützen wolle.
Die konvertieren anscheinend bisher immer von HDF5 zu dem ROOT eigenen Zeug.

Aber euch beiden erstmal vielen Dank für die guten Tipps und einen schönen Tag!

p90
BlackJack

Hm, ein anderes Format für so mehrdimensionale Messdatenfelder was auch eine gewisse Verbreitung hat ist netCDF und *das* setzt mittlerweile intern auch auf HDF. Ist ROOT dann so eine Art gallisches Dorf das sich als letzte standhaft gegen die Römer, äh, HDF wehrt‽ :D
Antworten