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

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

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: Alles auswählen

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)]
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: 4881
Registriert: Donnerstag 20. Juli 2006, 23:06
Wohnort: Berlin

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:

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

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

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

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

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

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

Code: Alles auswählen

#!/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'
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.
BlackJack

@epsilon: Kannst Du Deinen Benchmark vielleicht noch einmal Verfügbar machen? Der Paste ist anscheinend nach der Umstellung von ubuntuusers weg.

@BastiL: Wie sieht's mit der Zeit aus, wenn Du auch wirklich die Daten extrahierst und in eine Datei schreibst?
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Das mit der Zeit für extrahieren und Schreiben müsste ich mir ansehen. Das ist allerdings im benchmark von Epsilon auch nicht dabei, das ist auch die reine Suchzeit. Das Schreiben geht gefühlt auf jeden Fall schneller als das Suchen, die gesamte Programmlaufzeit liegt für meinen Code unter 30 Sekunden.
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

Über den Cache von Google ist das Skript noch verfügbar (Hier mit Formatierung)

Das Skript hatte noch einen bug, wodurch in byteweise() immer die Selbe Anzahl an Bytes eingelesen wurde. Der Unterschied ist allerdings gering (falls es überhaupt einen Unterschied gibt):

mem: 6.33056998253 Sekunden
mmap: 6.20173692703 Sekunden
104857 Byte: 6.86206698418 Sekunden
10485760 Byte: 6.63443303108 Sekunden
104857600 Byte: 6.43973302841 Sekunden
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Irgendwie hat mir das bisher nicht so ganz weitergeholfen. Was ich im Moment v.a. nicht verstehe ist der große Performenceunterschied zwischen meinem Skript und der "mem" Variante im Benchmark von epsilon. Das Einlesen ist ja genau gleich, anscheinend liegt das im Matchen es re? Ich muss da mal ein paar Tests fahren... Habt Ihr noch Ideen?
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

BastiL hat geschrieben:[...] Was ich im Moment v.a. nicht verstehe ist der große Performenceunterschied zwischen meinem Skript und der "mem" Variante im Benchmark von epsilon. Das Einlesen ist ja genau gleich, anscheinend liegt das im Matchen es re? Ich muss da mal ein paar Tests fahren... Habt Ihr noch Ideen?
Das kann ich mir ehrlich gesagt auch nicht erklären. Das Einzige, was ich mir denken könnte, ist dass du nicht den selben Regulären Ausdruck verwendet hast (hast du auch die Flags ausgetauscht? Also dein 're.I' gegen mein 're.S | re.U' ? Wenn nicht, teste das mal.).

Dann frage ich mich noch, wie du in 10 Sekunden 2 GB einlesen und den RE drüber laufen lassen willst? (Ich brauche alleine für das einlesen von 1 GB 30 Sekunden, und das ist das reine einlesen. Vielleicht hast du aber auch nur 'ne besser Festplatte als ich ;))

Dann frage ich mich noch: Hast auch (wie ich) für jeden Test eine andere file verwendet, bzw. vor jedem Test den Cache gelöscht? Benen' doch mal deine Testfile um und teste mit ihr dein Testskript, nachdem du meine 'mem' Funktion verwend hast.

BastiL hat geschrieben:Irgendwie hat mir das bisher nicht so ganz weitergeholfen.
Hast du überhaupt getestet, ob man mit mmap auf einem 64-Bit System größere Dateien als 2 bis 3 GB adressieren kann? Vom speed her darf ja mmap eigentlich gar nicht langsamer sein als das direkte, komplette Einlesen in den Speicher (wenn man auf jede Stelle in der file sowieso nur einmal mit dem RE zugreift). In meinen Tests war mmap sogar ein wenig schneller als das Einlesen in den Speicher.
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

epsilon hat geschrieben: Das Einzige, was ich mir denken könnte, ist dass du nicht den selben Regulären Ausdruck verwendet hast (hast du auch die Flags ausgetauscht? Also dein 're.I' gegen mein 're.S | re.U' ? Wenn nicht, teste das mal.).
Das habe ich nicht. Mein Programm hat nach wie vor den Flag re.I, das Benchmark von Dir re.S | re.U. Das macht wohl den Unterschied und das muss ich mir jetzt ansehen.
epsilon hat geschrieben:Dann frage ich mich noch, wie du in 10 Sekunden 2 GB einlesen und den RE drüber laufen lassen willst? (Ich brauche alleine für das einlesen von 1 GB 30 Sekunden, und das ist das reine einlesen. Vielleicht hast du aber auch nur 'ne besser Festplatte als ich ;))
Um ehrlich zu sein macht das mein Rechner nicht ich ;) Ich kann nicht so schnell lesen....
Dann frage ich mich noch: Hast auch (wie ich) für jeden Test eine andere file verwendet, bzw. vor jedem Test den Cache gelöscht? Benen' doch mal deine Testfile um und teste mit ihr dein Testskript, nachdem du meine 'mem' Funktion verwend hast.
Nein ich verwende dasselbe File. Dein Pfad zeigt doch auch immer auf die gleiche Datei?? Bei meinem Benchmark habe ich lediglich den Pfad geändert - zeige aber immer auf dieselbe Datei, genau wie Du....
Hast du überhaupt getestet, ob man mit mmap auf einem 64-Bit System größere Dateien als 2 bis 3 GB adressieren kann?
Noch nicht. Das muss ich machen, dazu gibt es im Netz durchaus widersprüchliche Infos...
Vom speed her darf ja mmap eigentlich gar nicht langsamer sein als das direkte, komplette Einlesen in den Speicher (wenn man auf jede Stelle in der file sowieso nur einmal mit dem RE zugreift). In meinen Tests war mmap sogar ein wenig schneller als das Einlesen in den Speicher.
Korrekt. Daher wäre das für mich der Weg wenn das mit Files > 2GB läuft...
Ich melde mich wieder wenn ich die Tests gefahren habe.
epsilon
User
Beiträge: 71
Registriert: Freitag 20. Juni 2008, 19:48

BastiL hat geschrieben: Nein ich verwende dasselbe File. Dein Pfad zeigt doch auch immer auf die gleiche Datei?? Bei meinem Benchmark habe ich lediglich den Pfad geändert - zeige aber immer auf dieselbe Datei, genau wie Du....
Ne ich hab's immer mit 'ner anderen file getestet (siehe hier):
dewiktionary-20080617-pages-articles00.xml
dewiktionary-20080617-pages-articles01.xml
dewiktionary-20080617-pages-articles02.xml
dewiktionary-20080617-pages-articles03.xml
dewiktionary-20080617-pages-articles04.xml
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Also: wenn ich die Flags in meinem (schnellen) Skript tausche (re.S | re.U statt re.I) dann bleibt das Tempo gleich hoch, genauso wenn ich statt meinem re.search dein re.compile verwende.... Dein Skript bleibt deutlich langsamer.... Keine Ahnung warum...

Das Problem 2GB Grenze bleibt: wenn ich mmap verwende bekomme ich:

OverflowError: memory mapped size is too large (limited by C int)

Das scheint wohl auch ein Problem der Implementierung von Python 2.4.2 zu sein, selbst wenn ich die 64 Bit Version verwende (was ich gar nicht weiss - wie finde ich das heraus?)
Leonidas
Python-Forum Veteran
Beiträge: 16025
Registriert: Freitag 20. Juni 2003, 16:30
Kontaktdaten:

Ich weiß grad nicht wie das bei Windows aussieht (müsste aber in sys.version stehen), aber eine Methode das herauszufinden ist:

Code: Alles auswählen

>>> sys.maxint == 2**(32-1)-1
False
>>> sys.maxint == 2**(64-1)-1
True
My god, it's full of CARs! | Leonidasvoice vs (former) Modvoice
BastiL
User
Beiträge: 135
Registriert: Montag 7. Juli 2008, 20:22

Leonidas hat geschrieben:Ich weiß grad nicht wie das bei Windows aussieht (müsste aber in sys.version stehen), aber eine Methode das herauszufinden ist:

Code: Alles auswählen

>>> sys.maxint == 2**(32-1)-1
False
>>> sys.maxint == 2**(64-1)-1
True
So sieht das bei mir auch aus. Ist kein Win sondern 64Bit Linux. Die Binary ist auch 64-bittig...
Antworten