| Autor |
Beitrag |
Niko S.
      
Beiträge: 566
Erhaltene Danke: 10
Win 7, Ubuntu
Lazarus, Turbo Delphi, Delphu 7 PE
|
Verfasst: Fr 03.07.09 17:18
Also ich wollte für eine Mapdatei meine Einträge in eine typisierte Datei packen ganz nach dem Beispiel
im Delphi-treff.de.
Aber irgendwie glaube ich, dass das recht langsam geht, ich brauche für 65535 Einträge knapp ne Sekunde.
Mein System:
-Athlon X2 1,9 ghz
-2gb ram
-win 7 / vista
-Ausbalanciert (Laptop)
Hier mal die Routine
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| procedure TForm1.LoadMap(Datei: String); var i,i2,q:Integer; Mapfile: file of TMap; CurMap: TMap; begin q := 0; AssignFile(MapFile, Datei); ReSet(MapFile); for i := 0 to 255 do begin for i2 := 0 to 255 do begin if (q<0) or (q>=FileSize(MapFile)) then exit else begin seek(MapFile, q); read(MapFile, CurMap); Map[i,i2].ground[0] := CurMap.Ground[0]; Map[i,i2].ground[1] := CurMap.Ground[1]; Map[i,i2].mask1[0] := CurMap.mask1[0]; Map[i,i2].mask1[1] := CurMap.mask1[1]; Map[i,i2].mask2[0] := CurMap.mask2[0]; Map[i,i2].mask2[1] := CurMap.mask2[1]; Map[i,i2].overlay1[0] := CurMap.overlay1[0]; Map[i,i2].overlay1[1] := CurMap.overlay1[1]; Map[i,i2].overlay2[0] := CurMap.overlay2[0]; Map[i,i2].overlay2[1] := CurMap.overlay2[1]; Map[i,i2].event := CurMap.event; end; inc(q); end; inc(q); end; CloseFile(MapFile); end; |
Sind halt meine Anfänge in typisierten Datein, wenn ich da was besser machen kann, sagt es ruhig.
|
|
jaenicke
      
Beiträge: 19346
Erhaltene Danke: 1754
W11 x64 (Chrome, Edge)
Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
|
Verfasst: Fr 03.07.09 17:31
Wozu seekst du jedes Mal?
Du seekst doch ohnehin nur immer an die Position, an der du vorher schon warst.
|
|
Niko S. 
      
Beiträge: 566
Erhaltene Danke: 10
Win 7, Ubuntu
Lazarus, Turbo Delphi, Delphu 7 PE
|
Verfasst: Fr 03.07.09 17:45
Nein eben nicht?
Also das Seeken ist doch, soweit ich verstanden habe zum Positionieren.
Und da ich q immer wieder incrementiere, seeke ich nicht an die Selbe stelle o: ?
|
|
SvenAbeln
      
Beiträge: 334
Erhaltene Danke: 3
|
Verfasst: Fr 03.07.09 19:28
Durch das Read wird die Position in der Datei schon weiter gezählt.
Mit deinem Seek setzt du die Position danach noch einmal auf genau die selbe Stelle.
|
|
Niko S. 
      
Beiträge: 566
Erhaltene Danke: 10
Win 7, Ubuntu
Lazarus, Turbo Delphi, Delphu 7 PE
|
Verfasst: Fr 03.07.09 19:51
Ah! Okay das wusste ich nicht.
Aber trotzdem nicht schneller geworden.
//edit
Ich hab das grad mal ins TXT format gebracht mit ; getrennt und mit jaenickes vorschlag aus dem thread
www.delphi-forum.de/...ei+parsen_93414.html
probiert und es ist knapp 50% schneller, ich haette gedacht, dass txt operationen langsamer wären als diese typisierte sache, aber anscheinend irre ich mich da wohl.
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 03.07.09 21:21
Wie ist die Struktur deklariert, die Du einliest? Könntest Du das bitte mal mit angeben. Ich denke, das dürfte sich UM EINIGES verenfachen und beschleunigen lassen ...
Wenn alle Befehle bei Dir in der Reihenfolge der Deklaration stehen und das der gesamte Record ist, geht es auch einfach so:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16:
| procedure TForm1.LoadMap(Datei: String); var i,i2:Integer; Mapfile: file of TMap; CurMap: TMap; begin AssignFile(MapFile, Datei); Reset(MapFile); for i := 0 to 255 do begin for i2 := 0 to 255 do begin read(MapFile, CurMap); Map[i,i2] := CurMap; end; end; CloseFile(MapFile); end; |
Da du zudem die Daten so aus der Datei liest, wie sie eh im Speicher liegen, geht es auch noch einfacher:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11:
| procedure TForm1.LoadMap(Datei: String); var Mapfile: TFileStream; begin MapFile := TFileStream.Create(Datei, fmOpenRead + fmShareDenyWrite); try MapFile.read(Map, SizeOf(Map)); finally FreeAndNil(MapFile); end; end; |
Das funktioniert aber nur, WENN Map EIN STATISCHES ARRAY IST!
Anmerkung: Beide Methoden vertragen keine Ansi- oder WideStrings (genauso wenig wie die FileOf-Variante).
P.S.: Die letzte Variante ist in der Performance allein durch die Festplatten-Performance beschränkt ...
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Niko S. 
      
Beiträge: 566
Erhaltene Danke: 10
Win 7, Ubuntu
Lazarus, Turbo Delphi, Delphu 7 PE
|
Verfasst: Fr 03.07.09 22:02
Jetzt bin ich beeindruckt...
Dankeschön, die Datei wird nun innerhalb 10 ms geladen =D
Ich werd mich dann wohl mehr mit Filestreams außeinander setzen.
Gruß
Niko
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 03.07.09 22:20
Der Trick dabei ist, dass jede Lese- oder Schreiboperation einen gewaltigen Overhead im Betriebssystem erzeugt. Daher sollte man immer schauen, dass man so große Blöcke wie möglich mit einem Schlag lesen oder schreiben kann, da dieser Overhead dann nur einmalig anfällt. Bei deiner Ausgangsroutine ist der Overhead 65536 mal angefallen zzgl. der dauernden Abfragen auf die Dateigrößen. Jegliche Angaben, die man einmal ermittelt, sollte man soweit es geht zwischenspeichern, damit man diese nicht ständig neu ermitteln muss.
Wenn man auf Grund der Dateistruktur keine großen Blöcke am Stück lesen kann (viele kleine, unstrukturierte Informationen), dann gibt es oftmals einen anderen Weg: Zwischenpuffern. Dabei liest man aus der Datei z.B. 4KB ein, obwohl man vielleicht nur 3 Byte braucht. Man kann dann nämlich im nächsten Schritt bis zu 4k-3 Byte Zugreifen, ohne das Dateisystem zu bemühen, was gerade bei umfangreichen Strukturen eine Menge Zeit einspart. Ferner bietet es sich an, Lesevorgänge auf Vielfache von 512 Byte bzw. 4k zu optimieren, da Lowlevel-Zugriffe mindestens auf Sektor-Ebene stattfinden (512 Byte), das Memory-Management von Windows aber auf 4k-Blöcke ausgelegt ist. Wenn man also miteinem Schlag 4k liest, (also 8 Sektoren einer Platte, bzw. 1 Cluster), braucht der Plattentreiber intern nichts lesen, was er später wieder verwerfen müsste.
Durch Experimente mit der Blockgröße kann man u.U. noch einige Prozente an Performance rausholen, was sich aber in den seltensten Fällen lohnt, bzw. sinnvoll vorhersagen lässt. Wenn man also ein Kopierprogramm schreibt, bringt es nichts, mit einem Lese-Puffer von z.B. 64 MB zu arbeiten, da dieser mit hoher Wahrscheinlichkeit im physikalischen Speicher fragmentiert liegt, also wieder Sektoren mit unter einzeln gelesen werden müssen. Mit einem 64k-Puffer ist diese Gefahr wesentlich geringer, weshalb hier je nach Quell- und Zielmedium die Performance mit einem kleinen Puffer u.U. größer ist.
Für deinen Fall zum Lesen einer einfachen Datenstruktur, die nicht gerade mehrere MB groß ist, spielen solche Entscheidungen aber nur selten eine bedeutsame Rolle. Das Schnellste ist hier immer, wenn nach dem Lesen die Verarbeitung stattfindet (sofern noch nötig), das Lesen selber aber auf einem Punkt konzentriert ist.
OT: 10ms mit GetTickCount oder QPF\QPC gemessen??? Mit GetTickCount wäre ein solcher Messwert nämlich wenig aussagekräftig, da GetTickCount viel zu ungenau misst.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Niko S. 
      
Beiträge: 566
Erhaltene Danke: 10
Win 7, Ubuntu
Lazarus, Turbo Delphi, Delphu 7 PE
|
Verfasst: Fr 03.07.09 22:38
QPF/QPC natürlich.
Naja die Map datein werden schon knapp 3MB groß, allerdings im unkomprimierten zustand...
Wenn die Map an sich leer ist, also viele einträge sich wiederholen, dann ist die Map unter 200kb groß.
Und klar Strukturiert:
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8:
| TMap = record ground : array[0..1] of Integer; mask1 : array[0..1] of Integer; mask2 : array[0..1] of Integer; overlay1 : array[0..1] of Integer; overlay2 : array[0..1] of Integer; event : integer; end; |
Und hat ne feste größe, also geht das mit dem FileStream wunderbar, das habe ich gar nicht gewusst,
ich habe mich schon gefragt was ist, wenn ich ca 30-40 Maps laden müsste...
Aber gut zu wissen, dass es auch anders geht.
Und mal zu dem "Ansi", heißt dass, wenn ich in einem record "Strings" verwende, dass ich dann schwierigkeiten bekomme,
so über einen Filestream die Datei zu speichern?
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 03.07.09 22:50
Schwierigkeiten direkt nicht, aber in diesem Falle ginge es dann nicht mehr mit einem Lesezugriff allein, wie es jetzt der Fall ist.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
|