Speicherplatz-Optimierung

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
uselessuser
User
Beiträge: 8
Registriert: Dienstag 29. Mai 2007, 20:54

Hallo Forum,

ich bin gerade ein wenig verzweifelt. Ich brauche eine Moeglichkeit, gigantisch lange Listen mit Float-Werten zu speichern, und zwar so, dass sie moeglichst wenig Platz brauchen und auch schnell wieder einlesbar sind.

Bisher habe ich das ganz naiv mit Listen versucht. Diese werden inkrementell erstellt, also einfach immer ein Float hinten angehangen, und wenn sie fertig sind, werden sie mit cPickle auf die Platte geschrieben.

Gibt es eine Moeglichkeit, Listen auf bestimmte Datentypen zu begrenzen? Mir Arrays sollte das ja gehen, aber dafuer bin ich zu bloed, scheint's. Allerdings habe ich auch keine gute Doku gefunden.
Ich wuerde meine Flaots * 1000 oder so nehmen, als int casten und dann in die Liste schreiben. Hat Python die Moeglichkeit, kleinere Einheiten als gleich Ints zu verwenden? Shorts oder so? Wenn ja, nehmen die in einer Liste weniger Platz weg als ein Int? Oder ist pro Element der Liste eine gewisse Menge Speicher reserviert?

Gibt es auch noch eine Moeglichkeit, mit cPickle Platz zu sparen? cPickle ist vorgegeben, da komme ich nichr drum herum. Bislang sollte auch alles nicht-binaer sein, bringt Binaer-Codierung deutliche Vorteile?


Das sind ein bisschen viele Fragen, aber ich bin gerade ein wenig kopflos. Die Sache muesste streng genommen schon fertig sein...
BlackJack

Von welchen Grössenordnungen reden wir denn?

Schau doch mal das `array`-Modul an.
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Wenn pickle vorgegeben ist verwendest du halt pickle um die String Form des Arrays zu speichern.

Irgend wie sowas pickle.dumps(array('f', [1.0, 2.0, 3.0]).tostring())
uselessuser
User
Beiträge: 8
Registriert: Dienstag 29. Mai 2007, 20:54

Die Vektoren haben 1.000.000 Stellen, und ich will so viele wie moeglich erzeugen koennen (oberes Limit ist wiederum ca 1.000.000). Mehr als 1 Terabyte habe ich aber nicht.

Mit Arrays exerimentiere ich geade herum. Sind die nur schneller, oder auch speicherfreundlicher als Listen?
uselessuser
User
Beiträge: 8
Registriert: Dienstag 29. Mai 2007, 20:54

veers hat geschrieben:Wenn pickle vorgegeben ist verwendest du halt pickle um die String Form des Arrays zu speichern.

Irgend wie sowas pickle.dumps(array('f', [1.0, 2.0, 3.0]).tostring())
Uh, Strings auf der Platte sind sicher nochmal groesser..? Das wollte ich ja vermeiden.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

uselessuser hat geschrieben:cPickle ist vorgegeben, da komme ich nichr drum herum.
Hallo uselessuser!

Ich halte das für gekneteten Schwachsinn! :roll: Du musst cPickle nehmen? Schwachsinn, Schwachsinn, Schwachsinn!!! Entweder du darfst optimieren oder du musst cPickle nehmen. Beides wird wohl nicht optimal funktionieren.

Du kannst mit array -- vielleicht auch mit struct -- wunderbar optimieren -- aber gleichzeitig cPickle verwenden? Das ist wie "Schlag mich, aber hau mich nicht."

mfg
Gerold
:-)

PS:

Code: Alles auswählen

>>> import array
>>> a = array.array("f")
>>> for i in xrange(1000000):
...     a.append(i)
...     
>>> f = file("data.dat", "wb")
>>> a.tofile(f)
>>> f.close()
>>> b = array.array("f")
>>> f = file("data.dat", "rb")
>>> b.fromfile(f, 1000000)
>>> print b[0]
0.0
>>> print b[1]
1.0
>>> print b[2]
2.0
>>> f.close()
>>>
Das mit diesem Code erstellte File braucht auf der Festplatte exakt **3,81 MB (4.000.000 Bytes)**.
Wenn du größere Zahlen brauchst, dann kostet dich jeder Wert 8 Byte. Denn statt "f" gibst du dann einfach "d" an beim Erstellen des Arrays.
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

...wenn du das oben erstellte Array (a) mit cPickle speicherst, dann ist die daraus resultierende Datei **3,81 MB (4.000.030 Bytes)** groß.

Natürlich mit ``pickle.HIGHEST_PROTOCOL`` gespeichert:

Code: Alles auswählen

f = file("picledarray.dat", "wb")
pickle.dump(a, f, pickle.HIGHEST_PROTOCOL)
f.close()
Der Unterschied:
**9,05 MB (9.499.114 Bytes)** kostet es dich, wenn du auf ``pickle.HIGHEST_PROTOCOL`` verzichtest.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gerold hat geschrieben:Ich halte das für gekneteten Schwachsinn! :roll: Du musst cPickle nehmen? Schwachsinn, Schwachsinn, Schwachsinn!!! Entweder du darfst optimieren oder du musst cPickle nehmen. Beides wird wohl nicht optimal funktionieren.
Und ich habe mich schon gewundert, warum du cPickle so schlimm findest. Ist es nämlich nicht, wenn man weiß wie man es denn genau einsetzen will. Aber man muss sagen, dass der Einsatz von Pickle in diesem Fall etwas unnütz ist, man kann das Array auch direkt in eine Datei schreiben.
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

Leonidas hat geschrieben:Und ich habe mich schon gewundert, warum du cPickle so schlimm findest.
Hallo Leonidas!

Nein, so schlimm ist es auch wieder nicht. Eigentlich regen mich immer nur solche Vorgaben auf, die für mich einfach keinen Sinn ergeben. Wie z.B. "Optimiere so gut wie möglich, aber du musst Pickle verwenden..." :roll:
Wem soll das etwas bringen? Soll ein anderes Programm auch auf die Daten zugreifen? Wenn ja, dann muss es sowiso eine Vereinbarung zwischen diesen beiden Programmen geben. Am Besten sogar ein gemeinsam genutztes Modul für den Datenzugrif. Usw.

Das wird wohl das Wetter sein, was mich so intolerant macht. ;-)

lg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

gerold hat geschrieben:Nein, so schlimm ist es auch wieder nicht. Eigentlich regen mich immer nur solche Vorgaben auf, die für mich einfach keinen Sinn ergeben. Wie z.B. "Optimiere so gut wie möglich, aber du musst Pickle verwenden..." :roll:
Soleche vorgabe gibt es aber oft. Entwickle ein Programm, möglichst schnell, aber es muss Java nutzen. Oder C#. Ähmliches gilt auch für: schriebe einen performanten Netzwerkserver, aber der muss unter Windows laufen. Oder, oder, oder. Es gibt ja viele Vorgaben die einen oftmals stören, weil sie einfach nicht zielführend sind. Sich über alles zu ärgern bringt einen nicht viel weiter, man muss eher versuchen diese Vorgaben aufzulockern.
gerold hat geschrieben:Wem soll das etwas bringen? Soll ein anderes Programm auch auf die Daten zugreifen? Wenn ja, dann muss es sowiso eine Vereinbarung zwischen diesen beiden Programmen geben.
Ach, wer braucht schon Vereinbarungen? Mit XML geht alles ;)
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

uselessuser hat geschrieben:Die Vektoren haben 1.000.000 Stellen, und ich will so viele wie moeglich erzeugen koennen (oberes Limit ist wiederum ca 1.000.000). Mehr als 1 Terabyte habe ich aber nicht.
Hallo uselessuser!

Um wieder auf dein Problem zurück zu kommen. Welchen Bereich können deine Fließkommazahlen einnehmen? Von - Bis.

Wenn jede Zahl den gesamten Float- oder Double-Bereich abdecken muss, dann sehe ich Schwarz. Wenn du aber nur einen kleinen Teil daraus brauchst, dann könnte man da sicher etwas machen. Aber auch dann wenn du nur 256 Werte ausnutzt, also nur einen Byte pro Zahl brauchst, dann ist das bei 1.000.000 * 1.000.000 immer noch ein Terrabyte.

Irgendwie schwierig... :K

Vielleicht kommt ein Wert mehrfach hintereinander vor, dann könnte man den Wert und die Anzahl speichern, statt jeden Wert einzeln zu speichern...

EDIT:

Vielleicht könnte man da etwas mit dem Modul "zlib" machen. Ich werde mich mal ein wenig damit spielen.

mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
gerold
Python-Forum Veteran
Beiträge: 5555
Registriert: Samstag 28. Februar 2004, 22:04
Wohnort: Oberhofen im Inntal (Tirol)
Kontaktdaten:

gerold hat geschrieben:Vielleicht könnte man da etwas mit dem Modul "zlib" machen.
Hallo!

Ich habe in einem Durchlauf mit folgendem Programm 100 * 1.000.000 Werte gespeichert. Jedes Array mit je einer Mio. Fließkommazahlen wird zuerst komprimiert und dann in ein Shelve gespeichert.

Wenn man das auf 1 Mio. Datensätze hoch rechnet, dann brauche ich damit statt 4 bzw. 8 Terrabyte ca. 2.9 Terrabyte. Die Einsparung ist also zu gering.

Also einfach eine willkürliche Kompressionsmethode an die Daten zu lassen, bringt nichts.

Code: Alles auswählen

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-

import array
import zlib
import shelve
import pickle
import random


# Dummyarray mit zufälligen Werten
a = array.array("d", ( random.randrange(0, 32000) for i in xrange(1000000) ))

# Schreiben
sh = shelve.open("data.shelve", protocol = pickle.HIGHEST_PROTOCOL)
for i in xrange(100):
    print i
    sh[str(i)] = zlib.compress(a.tostring())
sh.close()

# Lesen
sh = shelve.open("data.shelve", protocol = pickle.HIGHEST_PROTOCOL)
keys = sh.keys()
keys.sort()
for index, key in enumerate(keys):
    b = array.array("d")
    b.fromstring(zlib.decompress(sh[key]))
    print b[index]
sh.close()
mfg
Gerold
:-)
http://halvar.at | Kleiner Bascom AVR Kurs
Wissen hat eine wunderbare Eigenschaft: Es verdoppelt sich, wenn man es teilt.
Benutzeravatar
nkoehring
User
Beiträge: 543
Registriert: Mittwoch 7. Februar 2007, 17:37
Wohnort: naehe Halle/Saale
Kontaktdaten:

Ich hab so das Gefuehl, dass da nur mathematische Methoden helfen, die speziell auf diese Listen zugeschnitten sind. Ich wuerde vorallem nach Duplikaten suchen... und evtl nach generierbaren Mustern...
[url=http://www.python-forum.de/post-86552.html]~ Wahnsinn ist auch nur eine andere Form der Intelligenz ~[/url]
hackerkey://v4sw6CYUShw5pr7Uck3ma3/4u7LNw2/3TXGm5l6+GSOarch/i2e6+t2b9GOen7g5RAPa2XsMr2
Benutzeravatar
veers
User
Beiträge: 1219
Registriert: Mittwoch 28. Februar 2007, 20:01
Wohnort: Zürich (CH)
Kontaktdaten:

Sehe ich das Richtig, es sollen 1'000'000 Zahlen mit jeweils 1'000'000 Stellen in eine Datei gespeichert werden? oder jeweils 1'000'000 mal Zahlen 1'000'000 mit 1000 Stellen auf ein TB Speichern? Ersteres ist "Problemlos". Beim zweiten fragt sich wie viel Redundanz in den Werten steckt...
uselessuser
User
Beiträge: 8
Registriert: Dienstag 29. Mai 2007, 20:54

So, da bin ich wieder.

Cool, dass sich hier einige Leute echt Muehe geben. Respekt!

Fuer die cPickle-Vorgabe ist schlicht und einfach mein Prof verantwortlich, und der gibt am Ende die Note. Ich soll nur die Daten erzeugen, er entpickelt die dann und arbeitet damit weiter. Und da er schon was geschrieben hat, das Pickle verwendet, muss ich das auch. So einfach ist das. :roll:

Um die Fragen zu beantworten, inzwischen bin ich zu der Einsicht gekommen, dass es keine negativen Werte geben wird. Der Rest des Wertebereichs kann theoretisch ganz ausgenutzt werden, aber wahrscheinlich nur sehr selten. Eventuell kann man sich da was ueberlegen, wie man die extrem hohen Werte auslagert. Der Mittelwert liegt wohl so bei 1000, mit einer Abweichung von nochmal 1000... sp Pi mal Daumen...

Was ich bisher versucht habe ist eine sparse representation, naemlich genau die Idee, gleiche Zahlen hintereinander als Tupel (Wert, Anzahl) zu speichern. Das bringt wahrscheinlich sogar recht viel, nur wie bekomme ich das in ein Array? In Listen ist das ja kein Problem.

veers, die Idee ist, 1.000.000 Dateien zu haben, die je 1.000.000 Zahlen beinhalten, die eben einen Haufen Nachkommastellen haben (je mehr desto besser, wobei eine Genauigkeit von mehr als 6, 7 Stellen wohl Unsinnig ist)


Derzeit glaube ich eher, alle Vektoren werden am Ende on demand erstellt. Dann muss der Rechner zwar permanent eine 8 GB-Datei im Speicher halten, und lahm wird's obendrein, aber dann muss man eben einen neuen Rechner kaufen ;)
BlackJack

Gibt's jetzt noch eine Frage? Und wenn ja, wie lautet die?

Ansonsten stell ich noch ein paar: es sollen eine Billion Fliesskommazahlen gespeichert werden!? In *einer* Datenstruktur? Oder in einer Million Datenstrukturen? Und wie soll darauf zugegriffen werden? komplett wahlfrei oder reicht der Zugriff auf jeweils ein "Millionen-Häppchen"?

Ein `array.array()` mit einer Million `float()`\s belegt grob 8 Megabyte Speicher. Wenn man C `float`\s nimmt, und deren Genauigkeit ausreicht, ist's nur der halbe Speicherbedarf.

Um Plattenplatz zu sparen, könnte es sich eventuell lohnen die Daten mit `zlib` oder `bz2` zu komprimieren. Beide stehen unter diesen Namen als Kodierung für die `encode()`/`decode()`-Methoden von Zeichenketten zur Verfügung. Ohne Komprimierung in irgendeiner Weise brauchen eine Billion Fliesskommazahlen "roh" ca. 8 bzw. 4 Terabyte, je nachdem ob man `float` oder `double` (beides C-Datentypen) verwendet.

Zu guter Letzt würde ich auch noch mal gerne `pickle` in Frage stellen. Bei grossen Datenmengen sind eigentlich Datenbanken gefragt. Bei *diesen* Grössenordnungen und der Art der Daten am besten spezielle Formate wie HDF5 oder netCDF, die auf grosse Mengen von Messdaten und Ähnliches spezialisiert sind.

http://en.wikipedia.org/wiki/HDF5
Antworten