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.
Speicherbegrenzung String
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.
Wenn der String ja eh in einem File gespeichert ist, besteht ja kein Grund, das ganze File auf einmal in einen String zu speichern.
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
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...
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
-
- 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
Kommt halt auf den Regex darauf an.
Gruss
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Hallo!
Gruß,
der Michel
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.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.
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)
der Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
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
Dateianfang
wenige MB
Beginn_Regex
2GB
Ende_Regex
Wenige MB
Ende Datei
audax hat geschrieben:oder ist die RegExp selbst auch 2gb?
- 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.
Wenn ja, kann man da nicht entweder nur die kurzen Enden (wenige MB) oder direkt die Übergänge suchen?
Gruß,
Michael
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.
Mir schwant, hier liegt ein groooßes Missverständnis vor. Meinst du vielleicht, dass das gefundene Resultat über 2GB groß werden kann??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
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 ...
- 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
bitte poste doch mal die ersten 2000-3000 Zeichen Deines re-Patterns.
Michel
Diese Nachricht zersört sich in 5 Sekunden selbst ...
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?
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...
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...
-
- 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
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
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
Grüße
-
- 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
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
- Michael Schneider
- User
- Beiträge: 569
- Registriert: Samstag 8. April 2006, 12:31
- Wohnort: Brandenburg
Hi BastiL!
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
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:Den Anfangs- und Endteil zu suchen habe ich versucht - erstaunlicherweise ist die Suchdauer DEUTLICH länger....
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.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...
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 ...
@ 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)
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)
@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.
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.