Performance beim Lesen von Dateien

Für allgemeine Fragen zur Programmierung mit PureBasic.
Marc
Beiträge: 9
Registriert: 03.11.2004 00:06

Performance beim Lesen von Dateien

Beitrag von Marc »

Hallo,

da ich mich nich wie vor nicht so recht zwischen PowerBasic und PureBasic entscheiden kann (gekauft hab ich eh beide und irgendwie haben beide ihre Vor- und Nachteile), habe ich ein wenig rumgetestet. Da ich gerade ein Programm brauchte, was eine Datei liest, habe ich auch genau das in beiden Basic-Dialekten programmiert und zum Vergleich noch ein Delphi-Programm mitlaufen lassen.

Powerbasic: 5,8 Sekunden
Delphi : 6,0 Sekunden
PureBasic: 46,6 Sekunden

Hm... ja, doch, hat was. Daß die Default-Routinen "etwas" langsam sind, wusse ich ja. Zugegebenermassen war ich jetzt auch zu faul, die von Rings entwickelten Routinen einzubinden und das Programm dahin gehend umzustricken.

Nur eine Frage: angenommen, ich stelle auf die alternativen Dateiroutinen um, werde ich dann bei der nächsten trivialen Aktion (als exotisch würde ich das Lesen von Dateien nun echt nich bezeichnen) wieder gegen den Baum laufen oder is das die einzige wirklich lahme Library?

Ach ja, und weiss jemand ob eine beschleunigte Version in v4.0 drin sein soll?

Gruß
Marc
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Zeig doch mal den Code her welchen du geschrieben hast und mit dem du das getestet hast. Vielleicht ist es ja nicht allein an PureBasic festzumachen sondern auch an deinem Programm (nicht bös' gemeint, nur sollte man auch in Betracht ziehen).
Marc
Beiträge: 9
Registriert: 03.11.2004 00:06

Beitrag von Marc »

Hi Sunny,

hab die schlauerweise nich griffbereit (liegen im Dienst),
aber alles was ich gemacht habe war

Datei öffnen
zeilenweise lesen bis EOF
Datei schliessen

selbst ich kann da nich viel falsch machen ;)
War aber auch nur die Kleinigkeit von 18 MB Textfile...

cu
Marc

Edit: habs noch mal eben rekonstruiert:

Code: Alles auswählen

handle = ReadFile(#PB_any, "x.txt")

If handle <>0
  While Eof(handle) = 0
    text$ = ReadString()
  Wend  
EndIf

Zuletzt geändert von Marc am 03.11.2004 00:49, insgesamt 1-mal geändert.
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Ich kann mich daran erinnern, dass mal jemand hier nach einer Möglichkeit gefragt hat, eine 100 MB große Textdatei zu schreiben mit Zufallszahlen. Ich hab eine Möglichkeit gepostet, hat ca. 50 Sekunden gedauert bis PB die Datei erstellt hatte (recht grob geschätzt, wobei 100 MB doch deutlich mehr als 18 Mb sind ;)).
Dann hatte später NicTheQuick noch eine andere Variante gepostet welche das alles in wenigen Sekunden abgehandelt hat. Also weeesentlich flotter. Vielleicht lässt sich da bei deinem Code auch noch einiges optimieren, auch wenn es erst nicht so aussieht. Es ging hierbei zwar um Schreiben und nicht Lesen aus Dateien, aber der Zugriff sollte doch recht ähnlich ablaufen und die Verbesserung von 50 auf vielleicht 5 Sekunden war schon enorm. ;)
Max.
Beiträge: 58
Registriert: 29.08.2004 13:19

Beitrag von Max. »

Ist mir bis jetzt noch nie so aufgefallen, wollte ich deshalb mal ausprobieren.

1. ~ 18MB Text Datei erstellen

Code: Alles auswählen

a=GetTickCount_()
bytes = 0
CreateFile(0,"c:\test.txt")
Repeat
  Output.s = " 123456789012345"
  bytes=bytes+Len(Output)
  WriteStringN(Output)
Until bytes>18000000
CloseFile(0)
Debug GetTickCount_()-a

Dauerte 2.2 Sekunden. :D

2. Auslesen

Code: Alles auswählen

a=GetTickCount_()
OpenFile(0,"c:\test.txt")
Repeat
  output.s=ReadString()
Until Eof(0)
CloseFile(0)
Debug GetTickCount_()-a
Knapp 12 Sekunden!? :shock:
AMD XP 2400+ · 1 GB RAM · Radeon 9800 Pro · Win XP SP1 · IE 6.0
Marc
Beiträge: 9
Registriert: 03.11.2004 00:06

Beitrag von Marc »

Beschleunigung um Faktor 10 wäre schon mal was :)

hier noch mal der komplette Test-Code:

Code: Alles auswählen

startzeit = ElapsedMilliseconds()

handle = ReadFile(#PB_any, "x.txt")

If handle <>0
  While Eof(handle) = 0
    text$ = ReadString()
  Wend  
EndIf

dauer = ElapsedMilliseconds() - startzeit
MessageRequester(Str(dauer), text$) 
braucht bei ner 14 MB Datei 28.4 Sekunden (P-IV 1.9 GHz), Delphi braucht 2.6 Sekunden.

Aus dem hohlen Bauch wüsste ich nicht, wo ich da Unsinn gebaut haben soll, aber denkbar ist alles :cry:
Benutzeravatar
Kiffi
Beiträge: 10719
Registriert: 08.09.2004 08:21
Wohnort: Amphibios 9

Beitrag von Kiffi »

> Beschleunigung um Faktor 10 wäre schon mal was :)

versuch mal die FastFile-Library
von Rings, die Deinen Code um einen
nicht unerheblichen Faktor beschleunigen sollte.

Grüße ... Kiffi
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Ich meine ja auch nicht, dass du da Mist gemacht hast, sondern dass man eben bei programmiersprachen schonmal optimieren muss. Muss man eigentlich immer und überall, manchmal mehr, manchmal weniger.

Hier mal ein Code welcher bei mir ~ 2,5 Sekunden zum Einlesen brauch:

Code: Alles auswählen

*buffer = AllocateMemory(17)
a=GetTickCount_()
OpenFile(0,"c:\test.txt")
Repeat
  laenge.l =ReadData(*buffer, 17)
Until Eof(0)
CloseFile(0)
MessageRequester("", Str(GetTickCount_()-a))
Dabei wird zuerst ein Speicherbereich mit 17 byte reserviert und dann wird direkt in diesen Speicherbereich eingelesen, die Datei. Allerdings nicht als String sondern als Bytes als Zahlen, könnte man bei Bedarf jetzt in einen String wandeln. Da in der Vorgegebenen Datei von Max. (die 19,3 MB große Datei welche ich mit seinem Code erstellt habe) die Zeilenlänge immer 16 Stellen beträgt, kann man das hier imo ganz einfach so machen. Bei variablen Längen wird es anders sein, da müsste man entweder den Buffer größer machen oder dynamisch anpassen. Wobei ich ihn eher größer machen würde. Von 17 auf 2000 byte, dass wird wohl kaum einem Rechner mit ~1 Gbyte Ram heutzutage schaden.

Das Erstellen der Datei ist übrigends schneller getan wenn man anstelle von WriteStringN nur WriteString nimmt. Dann macht er zwar keine Reihen, aber bei diesem Test gehts ja nur um die Anzahl an byte welche geselen werden können / Sek.

Hm, eigentlich könnte man doch auch gleich die ganze Datei einlesen, per ReadData in den Buffer... Und zu Testzwecken, ob er auch korrekt einließt, direkt wieder Schreiben in die Datei "text____2.txt":

Code: Alles auswählen

a=GetTickCount_()
*buffer = AllocateMemory(18000016)    ;Bei mir sind es exakt so viele Bytes in der Textdatei, bei Bedarf anpassen
a=GetTickCount_()
OpenFile(0,"c:\test.txt")
output.l =ReadData(*buffer, 18000016)
CloseFile(0)
MessageRequester("", Str(GetTickCount_()-a))
a=GetTickCount_()
OpenFile(1, "c:\text___2.txt")
WriteData(*buffer, 18000016)
CloseFile(0)
MessageRequester("", Str(GetTickCount_()-a))
Es dauer übrigends 0,4 Sekunden um diese Datei zu schreiben, das Einlesen dauert ca. 0,047 Sekunden, also extrem flott für 17 MB. ;)

Ach ja, ich hab eine 100 MB größe Datei in 5 Sekunden ausgelesen und in den Buffer geschrieben. Nachteil daran, man benötigt 100 MB im RAM. Allerdings braucht man diesen Speicher auch, wenn man die Zeilen einzeln einließt und in verschiedenen Strings speichert. Also da kommst du nicht drum herum, es sei denn, du ließt nur immer eine Zeile und schreibst diese gleich wieder auf die Festplatte und überschreibst den gleichen Speicher dann wieder mit der neuen Zeile.

Noch was, für Messergebnisse NIEMALS den Debugger anlassen, somit NIE per "Debug" etwas messen lassen. Lieber mit Messagerequester, da der Debugger natürlich alles etwas langsamer macht.


//EDIT:
versuch mal die FastFile-Library
von Rings, die Deinen Code um einen
nicht unerheblichen Faktor beschleunigen sollte.
Ich glaube, gerade auf solche Dinge von "3.-Anbietern" wollte er Verzichten. So hab ich das aus seinem ersten Beitrag herausgelesen.
Max.
Beiträge: 58
Registriert: 29.08.2004 13:19

Beitrag von Max. »

Sunny hat geschrieben:Ich meine ja auch nicht, dass du da Mist gemacht hast, sondern dass man eben bei programmiersprachen schonmal optimieren muss. Muss man eigentlich immer und überall, manchmal mehr, manchmal weniger.
Sorry, Du verwechselst Äpfel mit Birnen. Es ging um das zeilenweise Auslesen einer Text Datei mit den Standard-Befehlen, wobei PB dabei im Vergleich äusserst schlecht abschneidet.

Als ob A frägt, warum beschleunigt mein BMW mit 150 PS langsamer als der Mercedes des Nachbarn. Und dann kommst Du daher: "Ja, Mann, dat musste tieferlechen. Und digge Schlappen druff. Nen Bose-Endtopf draufgedengelt und dann noch die Noggenwelle, Alder, denk an die Noggenwelle!" :lol:

Wie auch immer, das Problem damit beschreibst Du ja selbst:
Bei variablen Längen wird es anders sein, da müsste man entweder den Buffer größer machen oder dynamisch anpassen. Wobei ich ihn eher größer machen würde. Von 17 auf 2000 byte, dass wird wohl kaum einem Rechner mit ~1 Gbyte Ram heutzutage schaden.
Dass der Code optimiert werden kann, ist klar (gibt auch schöne API Funktionen dafür). Aber wenn schon, dann auch bitte so, dass er vergleichbar ist; d.h. der eine Zeile einer Textdatei als String zurückgibt. Und nicht optimiert auf die eine Textdatei, die ich schnell zum Testen erstellt habe. Sowas machen nur Grafikkarten-Hersteller. :wink:

Und egal was Du machst, egal wie gut der Code ist, ändert das nichts daran dass ReadString bocklangsam ist. :wink:
AMD XP 2400+ · 1 GB RAM · Radeon 9800 Pro · Win XP SP1 · IE 6.0
Benutzeravatar
Danilo
-= Anfänger =-
Beiträge: 2284
Registriert: 29.08.2004 03:07

Re: Performance beim Lesen von Dateien

Beitrag von Danilo »

Marc hat geschrieben:Powerbasic: 5,8 Sekunden
Delphi : 6,0 Sekunden
PureBasic: 46,6 Sekunden
Genau aus diesem Grund gibt es die FastFile und FastFileText
Libraries.
Das Problem ist schon seit Jahren bekannt und Fred weiß auch
wie man es besser machen kann. Scheint ihn allerdings nicht
zu interessieren, da es die FastFile schon gibt.
cya,
...Danilo
"Ein Genie besteht zu 10% aus Inspiration und zu 90% aus Transpiration" - Max Planck
Antworten