Speicherbegrenzung String

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.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Hallo zusammen,

ich habe ein Skript das u.a. ein File in einem Rutsch in den Speicher liest. Die Files sind teils groß (mehr als 2GB) aber Arbeitsspeicher ist ausreichend da. Ich bekomme aber Probleme sobald das File größer ist als 2 GB dann läuft wohl intern etwas über (Max. length of string reached o.ä.) meint Python. Kann ich das irgendwie umgehen? Ansonsten läuft das Programm nämlich tipptop.

Danke.
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

Ich hab noch nie so ein Problem gehabt und vielleicht gibt es spezielle Module/Datentypen oder sonstwas dafür, aber eventuell könntest du den String auch einfach "häppchenweise" bearbeiten ;)
Wenn der String ja eh in einem File gespeichert ist, besteht ja kein Grund, das ganze File auf einmal in einen String zu speichern.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Hmm es geht um:

1. Performence - es muss im String zügig nach zwei Stellen gesucht werden mehr nicht

2. mache ich das Matching mit Regular Expessions - dafür brauche ich den String am Stück.

Grüße
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Warum brauchst du für Regex den String am Stück?

Wie sieht denn der Regex aus?

Gruss
Karl
User
Beiträge: 252
Registriert: Freitag 29. Juni 2007, 17:49

zu 2. Warum am Stück? Du kannst auch Teile des Strings untersuchen. Dass du dann eventuell deine gesuchte Stelle aufsplittest, sollte auch kein Problem sein. Das ist dann vielleicht wieder ein zusätzliches Problem für 1. Aber wenigsten's funktionierst ;)
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Weil ich von "Anfang" bis "Ende" suche... ud das ein SEHR langer Ausruck ist, der genau einmal vorkommt. Eigentlich ist mein Hauptziel, das File in drei Teile zu spalten und in zwei neuen Files zu sichern:
Alles vor "Anfang" und nach "Ende" landet in File1, alles dazwischen in File2.

Die Files sind:
1. groß (können auch noch größer werden als 2GB, habe ausreichend Speicher)
2. Eklig, weil es eine Mischung aus Ascii und Binär ist. Genau danach will ich das File teilen, alles zwischen Anfang und Ende ist binär. Interessanterweise läuft die Suche mit RegEx mit Abstand am schnellsten, wenn ich so suche. Dateianfang bis "Anfang" dauert z.B. viel länger...
rayo hat geschrieben:Hi
Warum brauchst du für Regex den String am Stück?
Wie sieht denn der Regex aus?
Gruss
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Ja aber wenn z.B. der Regex auf maximal 20 Zeichen matched kannst du 100MB einlesen, durchsuchen, falls nicht vorhanden lade die nächsten 100MB und pack aber 19 Zeichen vom vorherigen Block dran und nochmals suchen, usw.


Kommt halt auf den Regex darauf an.

Gruss
audax
User
Beiträge: 830
Registriert: Mittwoch 19. Dezember 2007, 10:38

oder ist die RegExp selbst auch 2gb?
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo!
rayo hat geschrieben:Ja aber wenn z.B. der Regex auf maximal 20 Zeichen matched kannst du 100MB einlesen, durchsuchen, falls nicht vorhanden lade die nächsten 100MB und pack aber 19 Zeichen vom vorherigen Block dran und nochmals suchen, usw.
Prinzipiell würde ich das auch so machen. Da dieses "dranpacken" der 19 Zeichen aber einen völlig neuen, überflüssigen String von über 100 MB generiert (=Zeit) solltest Du einfach den Dateizeiger relativ versetzen und dann wieder bis zu 100 MB einlesen, bis das Dateiende erreicht ist.

Code: Alles auswählen

# Generatorfunktion definieren
def chunk_gen(filepath, chunk_size=100*1024*1024, overlap=20):
    """Generatorfunktion, die den Inhalt von Datei filepath liefert

    filepath - vollstaendiger Dateipfad
    chunk_size - max. Groesse der Haeppchen in Bytes
    overlap - Anzahl der sich ueberlagernden Zeichen
    """
    import os
    length = os.path.getsize(filepath)
    file_input = open(filepath, "rb")
    try:
        while not file_input.tell() == length:
            if file_input.tell():    #  ueberspringe ersten Durchlauf
                file_input.seek(-overlap, 1)
            yield file_input.read(chunk_size)
    finally:
        file_input.close()

chunks = chunk_gen("c:\\test.dat")
for chunk in chunks:
    print "Laenge des Chunks:", len(chunk)
Gruß,
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Ja, die Regex ist 99,9% der Datei und damit 2GB groß. Kann auch noch größer werden. Das ganze sieht etwa so aus:

Dateianfang
wenige MB
Beginn_Regex
2GB
Ende_Regex
Wenige MB
Ende Datei
audax hat geschrieben:oder ist die RegExp selbst auch 2gb?
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi BastiL,

soviel ich weiß, arbeitet zumindest re rekursiv, was schnell das Rekursionslimit sprengen kann. Generell muss so ein regulärer Ausdruck erstmal kompiliert werden. Und was heißt, er kann auch noch größer werde - die haben normalerweise eine feste Länge.
BastiL hat geschrieben:Ja, die Regex ist 99,9% der Datei und damit 2GB groß. Kann auch noch größer werden. Das ganze sieht etwa so aus:

Dateianfang
wenige MB
Beginn_Regex
2GB
Ende_Regex
Wenige MB
Ende Datei
Mir schwant, hier liegt ein groooßes Missverständnis vor. Meinst du vielleicht, dass das gefundene Resultat über 2GB groß werden kann??
Wenn ja, kann man da nicht entweder nur die kurzen Enden (wenige MB) oder direkt die Übergänge suchen?

Gruß,
Michael
Diese Nachricht zersört sich in 5 Sekunden selbst ...
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hallo BastiL,

bitte poste doch mal die ersten 2000-3000 Zeichen Deines re-Patterns. ;-)

Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
BlackJack

Also mich würde auch der reguläre Ausdruck mal interessieren. Das ist nicht zufällig in der Mitte so etwas wie '.+' oder '.*' und davor und danach ein Ausdruck, der so etwas wie Anfangs- und Endmarkierung darstellt?
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Ok um das zu klären: Der RegEx selbst ist eine Zeile lang... Er matcht aber in dem File einen Bereich der größer als 2GB werden kann.

Den Anfangs- und Endteil zu suchen habe ich versucht - erstaunlicherweise ist die Suchdauer DEUTLICH länger....

Aber eigentlich kommen wir vom Thema ab - das Matchen ist nicht das Problem. Das Problem ist das Einlesen einer Datei mit mehr als 2GB "auf einen Rutsch" (f = read(Inputfile)) - da gibt es ein Limit in Python...
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Hi

Auch wenn es heutzutage kein Problem mehr ist, soviel RAM einzubauen, finde ich das vorgehen Files mit mehr als 2GB auf einmal in den RAM zu laden nicht so optimal.

Zeig uns doch mal den Regex, vielleicht kann man den ändern damit es schneller geht auf Anfang und Ende zu suchen.

Ich denke so einfach kann man das Limit von der maximalen Stringgrösse nicht ändern, kenn mich da aber auch überhaupt nicht aus.

Gruss
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Ich habe den Ausdruck grade nicht hier, poste ich morgen. Die Anwendung ist sehr speziell. Wir haben sehr große Files und gute Rechenaustattung. Daher ist es kein Problem. das File auf einmal einzulesen. Performence ist aber wichtig... Das heißt aber nicht das es vielleicht auch anders geht. Da ich aber wie schon gesagt das File aufteilen will werde ich nicht drumherum kommen, alles im Speicher vorzuhalten....

Grüße
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Nein alles brauchst du ja nicht im Speicher.

Falls du aus der einen Datei 3 Dateien machen willst kannst du folgendermassen vorgehen:
Lese 100MB ein, suche das Pattern, falls nicht gefunden schreibe es in die neue Datei 1, falls schon gefunden schreibe den 1. Teil in Datei 1, den Rest ab dem Pattern in Datei 2. Lese die nächsten 100MB ein und suche weiter (mit der Erwähnten überschneidung natürlich, FilePointer zurücksetzen)
Mit dem gleichen Schema kannst du auch den zweiten Teil der grossen Datei aufsplitten.

Somit hast du nur immer 100MB im Speicher, der Rest geht direkt wieder auf die Harddisk.

Das ganze geht natürlich nur wenn man den Regex in 2 einzelne Teile austeilen kann ohne dass er länger zum suchen hat.

Gruss
Benutzeravatar
Michael Schneider
User
Beiträge: 569
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Brandenburg

Hi BastiL!
BastiL hat geschrieben:Den Anfangs- und Endteil zu suchen habe ich versucht - erstaunlicherweise ist die Suchdauer DEUTLICH länger....
Das mag sein, aber Du musst die Ladezeit schon mit einrechnen. Und ich bin überzeugt, dass es länger dauert, >2GB in den Speicher zu laden, als vom Anfang bis Start und vom Ende bis zum Endpunkt und das dazwischen vom OS kopieren zu lassen oder häppchenweise umzuschaufeln.
BastiL hat geschrieben:Aber eigentlich kommen wir vom Thema ab - das Matchen ist nicht das Problem. Das Problem ist das Einlesen einer Datei mit mehr als 2GB "auf einen Rutsch" (f = read(Inputfile)) - da gibt es ein Limit in Python...
Wie Du sagst, das ist das Problem. Das hängt schon vom Dateisystem ab, denn z.B. mit FAT kannst Du unter Umständen nur max. 2GB adressieren. Das ist also kein Problem von Python, es sei denn Du nennst mir ein anderes Programm, mit dem Du mehr als 2GB auf Deinem Rechner einlesen kannst.
Das zu Deinem Thema.

Und nun zum Thema, dass es ABSURD ist, für eine minimale Anwendung 2 GB durch den Speicher zu jagen. Das belastet Deine Ressource ebenso immens wie unnötig. Insbesondere, wenn Du den String dann nur an 2 Stellen trennen möchtest und diese sogar noch sehr stark eingegrenzt sind. Du verrennst Dich da in einen völlig unpragmatischen Lösungsansatz.

Im Namen der Vernunft ;-): lass ab von Deinem Plane und poste das Pattern, dann gibt es hier sicher Fachleute, die elegantere UND schnellere Lösungen anbieten können.

Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

@ BastiL:

schau' dir mal mmap an ;)

http://effbot.org/tag/python.mmap
http://docs.python.org/lib/module-mmap.html

EDIT:

auf 32-bit Betriebssystemen kannst du damit allerdings auch nur 2 bis 3 GB-files verarbeiten. In dem Fall kannst du dir mal Pytables anschauen (http://www.pytables.org/moin). Siehe features 'Support of files bigger than 2 GB' (http://www.pytables.org/moin/MainFeatures)
BlackJack

@BastiL: Wie epsilon schon angedeutet hat, kann das einlesen von 2GB in den Speicher auch schon daran scheitern, dass bei 32-Bit Betriebssystemen der Adressraum eines einzelnen Prozesses in der Regel auf 2 bis 3 Gigabyte beschränkt ist, auch wenn mehr Speicher installiert sein sollte.

Wenn Du die Datei aufteilen möchtest belastest Du mit dem kompletten Einlesen den Speicher und die Dateisystem-Caches völlig unnötig mit der gesamten Datei. Wenn Du dann noch vorhaben solltest Dir von dem `match`-Objekt den Treffer als Zeichenkette zu holen, ist Dir hoffentlich klar, dass Du damit eine zweite Zeichenkette im Speicher erzeugst, die fast so gross ist wie die erste, eben nur abzüglich der paar MB vorn und hinten.

Eine ordentliche Lösung, die die Datei Stückweise verarbeitet, kann auch gar nicht so viel langsamer sein, weil die Laufzeit eigentlich vom Datentransfer zwischen Platte und RAM dominiert sein sollte. Wenn Du entsprechende Laufzeittests machst, musst Du immer die Caches vorher löschen, um aussagekräftige Ergebnisse zu bekommen. Nicht dass Du reguläre Ausdrücke mit Python-Schleifen bei Daten vergleichst, die schon längst im Speicher stehen.

Und spätestens wenn so eine "alles in den Speicher laden"-Lösung aus irgend welchen Gründen den verfügbaren Speicher sprengt und ausgelagert werden muss, hat man verloren was die Geschwindigkeit angeht.
Antworten