Große Liste mit compress komprimieren ... ???

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.
CapJo
User
Beiträge: 26
Registriert: Donnerstag 27. April 2006, 13:17

Mittwoch 14. Juni 2006, 10:36

7.15 zlib -- Compression compatible with gzip

For applications that require data compression, the functions in this module allow compression and decompression, using the zlib library. The zlib library has its own home page at http://www.gzip.org/zlib/. There are known incompatibilities between the Python module and versions of the zlib library earlier than 1.1.3; 1.1.3 has a security vulnerability, so we recommend using 1.1.4 or later.

compress( string[, level])

Compresses the data in string, returning a string contained compressed data. level is an integer from 1 to 9 controlling the level of compression; 1 is fastest and produces the least compression, 9 is slowest and produces the most. The default value is 6. Raises the error exception if any error occurs.

Es geht um eine Liste mit 2,5 Millionen Einträgen (22 MB) und die würde ich gerne mit compress komprimieren.

Leider verlangt compress einen String ... wie kann ich das Ganze casten? Und dann nach dem dekomprimieren wieder zurückcasten?

Ich könnts erst in einen String umwandeln ... und dann wieder mit eval einlesen, aber das dauert ewig. Da lohnt sich die Kompression dann gar nicht.

Gibts da ne Lösung um das ganze zur Laufzeit zu komprimieren?
[/quote]
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 14. Juni 2006, 10:43

Vielleicht mit Pickle

http://www.python.org/doc/1.5.2p2/lib/m ... ickle.html

Die "Dateien" die man übergeben muss, müssen lediglich objekte mit write(string) bzw read/readline sein, da kannst du dir einen Adapter zwischenbauen.
pr0stAta
User
Beiträge: 271
Registriert: Freitag 17. September 2004, 11:49
Wohnort: Bremen

Mittwoch 14. Juni 2006, 10:43

Leider verlangt compress einen String ... wie kann ich das Ganze casten? Und dann nach dem dekomprimieren wieder zurückcasten?
Casten ist hier wohl der falsche Ausdruck, aber egal :>
Ich weiss natürlich nicht wie deine Liste nun aussieht und wie das Kompremieren funktioniert, aber du könntest aus einer Liste einen langen
String mit einem bestimmten Trennzeichen machen, so könntest du nach dem dekomprimieren den string splitten
Beispiel wenn deine Liste die Zahlen 1-1000 hätte:

Code: Alles auswählen

test = ",".join([str(item) for item in range(1000)])
Nun hättest du einen langen String, 1,2,3,4,5,6....
Danach wieder aufsplitten:

Code: Alles auswählen

test2 = test.split(",")
Vielleicht hilft dir das ja weiter.
Gruss
CapJo
User
Beiträge: 26
Registriert: Donnerstag 27. April 2006, 13:17

Mittwoch 14. Juni 2006, 11:04

Danke für den Tipp pr0stAta, das Problem ist jedoch, dass da Integerwerte in der Liste stehen und ich müsste ja dann wieder auf jeden Wert in der Liste ein eval anwenden, da es ja nach dem splitten jetzt Strings sind.

In C oder in Java würd ich das ganze einfach in einen anderen Typ casten ... besteht ja sowieso alles aus 0en und 1en. Danach würd ichs komprimieren und dann wieder demkomprimieren und in den ursprünglichen Typ casten.

So würd das ganze am effizientesten gehen.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 14. Juni 2006, 11:14

In C oder in Java würd ich das ganze einfach in einen anderen Typ casten ... besteht ja sowieso alles aus 0en und 1en. Danach würd ichs komprimieren und dann wieder demkomprimieren und in den ursprünglichen Typ casten.
Dann zeig mir mal, wie du in Java ein int zu einem String castest ;)

Ne, mal ernsthaft: Pickle ist Pythons Ansatz, Variablen zu serialisieren, und dürfte auch dem entsprechend schnell sein.
Wenn du erstmal anfängst, dein Ding zu Parsen (denn nichts anders ist die split-Lösung) wird das mit ziemlicher sicherheit dem eigentlichen Ziel, nämlich weniger Speicherverbrauch entgegenwirken.

Aber mal davon ab, warum möchtest du die Liste Packen? 22MB sind ja eigentlich nicht soo die katasrophe.
Benutzeravatar
DatenMetzgerX
User
Beiträge: 398
Registriert: Freitag 28. April 2006, 06:28
Wohnort: Zürich Seebach (CH)

Mittwoch 14. Juni 2006, 12:26

die Liste packen??? für was. Was braucht mehr speicher. Die liste so zu belassen, oder die Liste zu komprimieren und bei jedem zugriff wieder dekomprimieren ;)

oder was falsch verstanden :roll:
CapJo
User
Beiträge: 26
Registriert: Donnerstag 27. April 2006, 13:17

Mittwoch 14. Juni 2006, 12:59

Die 22 MB sind jetzt der derzeitige Fall, es können aber auch schnell mal größere Datenaufkommen werden.

Es werden auf 32 Datenkanälen im microsekundenbereich Daten aufgezeichnet. Diese 22 MB sind in gerade mal in 1,25 Sekunden zusammengekommen.

Die Liste sollte gepackt werden, um Speicherplatz und Zeit, beim Ablegen der Daten, auf der Festplatte, zu sparen.
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Mittwoch 14. Juni 2006, 13:16

das dürfte "premature optimisation", und somit "the root of all evil" sein.

wenn das Problem ist, dass sich der Speicher zu schnell füllt, wirst du es nicht dadurch beheben, dass du den Speicherinhalt Packst, da weiterhin mehr reinkommen als rausgehen wird.

einen Geschwindigkeitsvorteil beim Schreiben auf die Platte wird sich auch nicht einstellen, da (aufgrund des Virtuellen Speichers) sich der krams evtl sowieso schon auf der Platte befindet.
Da dürfte es einfacher sein, aus sicht des Programmes die Daten einfach in eine Datei zu schreiben, die dann in einem gepackten Dateisystem liegt.

Kurz gefasst: Speichermanagement ist nicht Aufgabe deines Programms.
Joghurt
User
Beiträge: 877
Registriert: Dienstag 15. Februar 2005, 15:07

Mittwoch 14. Juni 2006, 13:22

Ich stimme mit keppla überein, dass es in deinem Falle schlecht ist, den String zu komprimieren.

Nur der Vollständigkeit halber hier eine Möglichkeit

Code: Alles auswählen

import zlib
import cPickle
l = range(100)
c = zlib.compress(cPickle.dumps(l))
del l
l = cPickle.loads(zlib.decompress(c))
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Mittwoch 14. Juni 2006, 13:32

CapJo hat geschrieben:besteht ja sowieso alles aus 0en und 1en.
Wie jetzt? Die Liste hat wirklich nur 0 und 1 ??? IMHO verbraucht dann ein String weniger Speicher, behaupte ich einfach mal so... Also warum dann nicht die "Daten" als String speichern?

Btw. was sind das für Daten, wenn es nur 0 und 1 ist???

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
CapJo
User
Beiträge: 26
Registriert: Donnerstag 27. April 2006, 13:17

Montag 19. Juni 2006, 10:45

Sorry, dass ich jetzt erst wieder Antworte ...

Das Modul, das wir benutzen, wurde in Indien implementiert und ist
in der derzeitigen Fassung nicht zu gebrauchen (viel zu lahm und viel zu großer Speicherverbrauch)... deshalb versuchen
wir da etwas zu optimieren

Also das ganze läuft wie folgt ab:

Die Daten kommen über einen C-Buffer als Array von Integerwerten (viele Millionen Werte) herein.

In diesem speziellen Fall sind das Spannungswerte, die im späteren Programablauf als Binärwerte interpretiert werden.

Diesen Buffer konnte man per cpickle nicht serialisieren und deshalb wurde aus diesem Array eine Liste gemacht und die kann man dann per dump ablegen.

Leider sind die Datenaufkommen sehr groß und deshalb sollte eine Kompression her, deshalb war die Idee Nahe Kompress zu benutzen.

Ein weiteres Problem ist mit cpickle aufgetreten, der will die Daten nicht in Binärform abspeichern obwohl ich das so angegeben habe.

... es wird hier aus Kompatibilitätsgründen die Python Version 2.2 benutzt.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 19. Juni 2006, 11:12

Macht es da nicht evtl. Sinn eine echte DB für her zu nehmen???

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Benutzeravatar
keppla
User
Beiträge: 483
Registriert: Montag 31. Oktober 2005, 00:12

Montag 19. Juni 2006, 12:11

Leider sind die Datenaufkommen sehr groß und deshalb sollte eine Kompression her, deshalb war die Idee Nahe Kompress zu benutzen.
Um welches Problem zu lösen? Denn Probleme könnte ich mir mehrere denken.

Wenn das Problem ist, dass du alle Daten vorrätig halten musst, ist Compress die falsche Lösung, imho, da du dann Speicher und Rechenzeit gegen Speicher tauscht (kompression/dekompression brauch ebenfalls Speicher).

Eigentlich gibt es dann nur zwei Fälle:
1. die Daten im Speicher sind "etwas" zu gross, dann ignorieren und auf virtuellen Speicher vertrauen, oder stückeln und auf die Platte schreiben, und bei Bedarf das nötige Stückchen laden.
2. die Daten sind "deutlich" zu gross, das schreit absolut nach Datenbank, denn da hilft dir dann auch Packen nicht, da du dabei ja nicht damit rechnen kannst, dass es dir immer 90% oder so wegkomprimiert.

Eigentlich lässt sich das vorgehen imho auf die Frage reduzieren: warum möchtest du die Daten überhaupt im Speicher haben? was genau willst du damit machen?
CapJo
User
Beiträge: 26
Registriert: Donnerstag 27. April 2006, 13:17

Montag 19. Juni 2006, 13:57

Danke für die Denkanstöße.

Die Daten müssen nicht dauerhaft im Speicher gehalten werden und die Daten sollten schnell ausgetauscht werden können. Die Datenmenge wird als Rohdaten aufgezeichnet (Integerwerte).

Diese Rohdaten sollen gespeichert werden um später dann ausgewertet zu werden.

Dabei wird die Datenmenge durchlaufen und eine grafische Ausgaben mit matplotlib gezeichnet.

Wir haben einen Lösungsansatz gefunden, der vielleicht nicht der elleganteste ist aber er war schnell implementiert.

Die Daten lagen als ctype-Array vor und werden in eine Liste gewandelt.

Diese wird per dumps aus cPickle in einen String umgewandelt und dieser String wird per compress aus dem zlib Modul komprimiert.

Anschließend wird per dump aus cPickle die Daten binär in eine Datei geschrieben.

Funktioniert wirklich gut und schnell.
Benutzeravatar
jens
Moderator
Beiträge: 8482
Registriert: Dienstag 10. August 2004, 09:40
Wohnort: duisburg
Kontaktdaten:

Montag 19. Juni 2006, 14:08

Wenn es nur INT Werte sind, wäre es IMHO schneller/kleiner ihr würtet statt cpickel einfach "-".join(...) / .split("-") nehmen ;) Pickel hat auch einen gewissen "Overhead"...

CMS in Python: http://www.pylucid.org
GitHub | Open HUB | Xing | Linked in
Bitcoins to: 1JEgSQepxGjdprNedC9tXQWLpS424AL8cd
Antworten