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: 116
Registriert: Montag 7. Juli 2008, 20:22

Beitragvon BastiL » Dienstag 8. Juli 2008, 22:26

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:

Beitragvon rayo » Dienstag 8. Juli 2008, 22:32

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: 566
Registriert: Samstag 8. April 2006, 12:31
Wohnort: Bremen
Kontaktdaten:

Beitragvon Michael Schneider » Dienstag 8. Juli 2008, 22:40

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

Beitragvon epsilon » Mittwoch 9. Juli 2008, 02:10

@ 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

Beitragvon BlackJack » Mittwoch 9. Juli 2008, 05:31

@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.
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

Beitragvon epsilon » Mittwoch 9. Juli 2008, 07:03

BlackJack hat geschrieben: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.


Du scheinst Recht zu haben. Laut meinem Testscript¹ ist der Unterschied minimal:

mem: 6.38910222054 Sekunden
mmap: 6.37096810341 Sekunden
0,1 MB-weise: 6.49766802788 Sekunden
10 MB-weise: 6.51032304764 Sekunden
100 MB-weise: 6.54638910294 Sekunden

Testdatei war ein XML-Dump des Wiktionary (157 MB), aus welcher ich die einzelnen Artikel extrahiert hab'.

¹ http://ubuntuusers.de/paste/390058/

PS: wobei das sicherlich alles andere als ein optimaler Test ist...
BastiL
User
Beiträge: 116
Registriert: Montag 7. Juli 2008, 20:22

Beitragvon BastiL » Mittwoch 9. Juli 2008, 09:30

Hallo zusammen,

ich habe 64 Bit Linux. Umgang mit Files größer 5 GB ist bei uns an der Tagesordnung. Nur mit Python bearbeite ich so etwas zum ersten Mal.

Ich poste mal einen Auszug aus meinem Code mit dem Pattern:

[code=]def Extract(File):
Part = re.search(r'\(0 "Grid:"\).*(?s)(?=\(0 "Thread variables:"\))', File, re.I)
return Part

f = open(sys.argv[1], "r")
print "lese " + sys.argv[1] + "..."
Casefile = f.read()
f.close()

Mittelteil = Extract(Casefile)
Teil1 = Casefile[0:Netz.start(0)]
Teil2 = Casefile[Netz.end(0):len(Casefile)][/code]

Was sicher nicht optimal ist, ist den langen regex durch kopieren auf Mittelteil kurz doppelt im Speicher zu haben. Aber es hat funktioniert und mir ist nichts besseres eingefallen. Jetzt ist wie gesagt das Problem, dass f.read bei Files > 2GB aussteigt. ich freue mich über Vorschläge.

Edit: Möglicherweise liegen die Performenceunterschiede am "r". Da das File Binärcode enthält wäre wohl "rb" die bessere Wahl, oder?
EyDu
User
Beiträge: 4866
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

Beitragvon EyDu » Mittwoch 9. Juli 2008, 09:55

epsilon hat doch schon eine Lösung gepostet, übernimm diese doch einfach. Wenn du Binärdaten verwendets, solltest du zum Öffnen in jedem Fall "rb" benutzen. Einfach nur "r" kann mit unter sogar falsche Ergebnisse liefern.

@epsilon: Warum benutzt du eigentlich immer Fußnoten, du kannst auch Links direkt im Text unterbringen :wink:
rayo
User
Beiträge: 773
Registriert: Mittwoch 5. November 2003, 18:06
Wohnort: Schweiz
Kontaktdaten:

Beitragvon rayo » Mittwoch 9. Juli 2008, 10:20

Hi

Also ich hab jetzt mal ein Beispiel gemacht ohne regulären Ausdruck.
Ist jedoch ungetestet! und hat einen grossen Fehler drin ;)

Durch die 25 Bytes, die überlappend sind, wird zuviel in den Part1 und Part2 geschrieben. Aber grundsätzlich sollte es so funktionieren, mit ein paar Index anpassungen geht das auch ohne die 25 Bytes die überlappen.

Das Beispiel ist nur der Wegweiser, wie es ohne die komplette Datei geht.

Beispiel

Ach ja ob "r" oder "rb": "rb" hat nur unter Windows einen Einfluss, unter Unix macht das keinen Unterschied, da bei Windows mit "r" ein \n zu \r\n wird mit "rb" nicht. Bei Unix bleibt \n auch ein \n, also kein Problem.

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

Beitragvon BastiL » Donnerstag 10. Juli 2008, 21:22

Danke. Ich werde das ganze mal ausprobieren. Melde mich dann nach den Tests nochmal.
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

Beitragvon epsilon » Samstag 12. Juli 2008, 13:11

EyDu hat geschrieben:@epsilon: Warum benutzt du eigentlich immer Fußnoten, du kannst auch Links direkt im Text unterbringen :wink:


Ich finde so geht es schneller, als wenn ich erst meine Hand den ganzen Weg zurück zur Maus bewegen muss ;)
BastiL
User
Beiträge: 116
Registriert: Montag 7. Juli 2008, 20:22

Beitragvon BastiL » Montag 21. Juli 2008, 06:59

Hallo zusammen,

ich habe endlich mal die Gelegenheit gehbat, mir das für eine meiner Beispieldateien anzuchauen. Mit dem Benchmark von epsilon bekomme ich für meine Beispieldatei mit meinem regulären Ausdruck folgendes:

mem: 114.707464933 Sekunden
mmap: 113.919741154 Sekunden
104857 Byte: 1291.05129695 Sekunden
10485760 Byte: 1293.54394603 Sekunden
104857600 Byte: 1293.17202592 Sekunden

Die Datei die ich jetzt benutzt habe ist knapp unter 2GB, deshalb werde ich gleich noch meinen bisherigen Algo laufen lassen und die Ergebnisse dazu auch noch posten. Der ist nämlich nochmal einiges schneller als mem....

Grüße
BastiL
User
Beiträge: 116
Registriert: Montag 7. Juli 2008, 20:22

Beitragvon BastiL » Montag 21. Juli 2008, 07:33

So, mit meinem Skript bekomme ich für dieselbe Datei:

Gesamtzeit: 10.3644731045 Sekunden

Das ganze läuft wie gesagt nur für Files < 2GB. Offensichtlich ist nicht nur das Laden in den Speicher ein Nadelöhr (bei meinen Files ungefähr Faktor 10) sondern auch noch die Art und Weise wie die reguläre Ausdruck behandelt wird (ich lese das File gleich ein wie die" mem"-Funktion von epsilon...)
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

Beitragvon epsilon » Montag 21. Juli 2008, 08:34

@ BastiL:

hast du Lust dein Testskript hier zu posten? Irgendwie kann ich mir nicht erklären, wieso das Einlesen in n-byte Blöcken mehr als 10-mal langsamer sein soll, als das direkte Einlesen der Datei oder der Verwendung von mmap. (Bei mir war ja alles ungefähr gleich schnell; siehe weiter oben)


So, mit meinem Skript bekomme ich für dieselbe Datei:

Gesamtzeit: 10.3644731045 Sekunden


Den Code würde ich auch mal gerne sehen, wenn es dir nichts aus macht.
Irgendwas muss ich falsch machen ;)
BastiL
User
Beiträge: 116
Registriert: Montag 7. Juli 2008, 20:22

Beitragvon BastiL » Montag 21. Juli 2008, 09:34

Mein Testscript entspricht Deinem, ich habe lediglich die RegEx geändert (nur den Teil zwischen den ''). Mein Code sieht so aus:

[code=]#!/usr/bin/python
# encoding: UTF-8

import sys, re, time

# Suchfunktionen
def Extract_Binary(File):
Binary = re.search(r'\(0 "Grid:"\).*(?s)(?=\(0 "Thread variables:"\))', File, re.I)
return Binary

# lese File in den Hauptspeicher
StartTime = time.time()
f = open(Test.file, "r")
print "lese Test.file"
File = f.read()
f.close()

print "analysiere "
Binaer = Extract_Binary(File)
print "Binärteil extrahiert"

print 'Gesamtzeit: ', time.time() - StartTime, 'Sekunden'[/code]

Wie ich oben schon geschrieben habe kann das an der speziellen Struktur meiner Files liegen. Dieses Tempo bekomme ich auch nur hin, wenn ich genau so matche - wenn ich von Dateianfang bis zum Auftreten von "(0 Grid)" suche dauert das auch deutlich länger.... Es ist aber auch denkbar, dass die großen Unterschiede erst bei großen Files (>> 1GB) auftreten.

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder