AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Programmierung allgemein Win32/Win64 API (native code) Delphi Viele Dateien performant einlesen

Viele Dateien performant einlesen

Ein Thema von Der schöne Günther · begonnen am 28. Apr 2014 · letzter Beitrag vom 30. Apr 2014
Antwort Antwort
Seite 4 von 4   « Erste     234
mensch72

Registriert seit: 6. Feb 2008
838 Beiträge
 
#31

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 21:45
..."Ich habe eine Vielzahl (ein paar Tausend) CSV-Dateien. Die möchte ich allesamt auswerten."...

Nun ja, ich hätte da ein paar Millionen(~3Mio) Dateien(a ~8KB) in ein paar tausend Verzeichnissen(~180000) und renne da ständig durch...

wo ist das Problem:
- über alle Dateien
* FileStream öffnen und StreamSize ermitteln
* bei den "Spielzeuggrößen" mit einem Schlag vom FileStream in RAM Buffer einlesen
* FileStream freigeben(schließen)
* keine Verarbeitung oder sonst was!
* nächste Datei
- Zeit messen

Man könnte auch hier zwar per WinApi Funktionen und direktem RAM Puffer ein paar MicroSekunden sparen, aber FileStream reicht hier vollkommen aus.
(Nebenbei: Bei "großen Dateien" einfach mal fach TFastfileStream googeln... da findet sich dann was schönes mit MemoryMappedFiles)

Wenn das OK, dann mit etwas Hirnschmalz ein eigenes "GetLine" geschrieben(einfach per BYTE Pointer durch den Rambuffer nach "CR" suchen und wenn CR gefunden es durch "NULL" ersetzen und die nun "NullTerminierte" Line ab vorherigem Pointer(bzw. anfangs "@0") weiter auswerten.

Gleiches Spiel nun innerhalb der Line. CSV-Trennzeichen fortlaufend suchen und gefundene Positionen+1 in BytePtrArray speichern und Inhalt des Pointers auf "0" setzen... Bingo: nun haben wir ohne jegliches Umkopieren irgendwelcher Speicher/Strings ein PtrArray mit lauter Pointern vom Typ PChar(bzw. PAnsiChar), welche wir problemlos verarbeiten, vergleichen, kopieren oder was auch immer können...


(Sorry für meine Vorliebe für NullTerminierte Strings auf Pointer-Basis, ich denke immer noch in "C" und nutze Delphi/Pascal nur weil es sein muss)

TStringList ist zwar schön, aber im Masseneinsatz ist deren LoadFromXXX als "ReadLN" doof. Wenn es schnell gehen soll, dann 3 Threads... 2x FileStreamLoad, 1x "RAM-CSV-Explode"... Results dann in weiterem Thread speichern/verarbeiten... damit sollte QuadCore gut ausgelastet werden.
Miniaturansicht angehängter Grafiken
miofiles.png  
  Mit Zitat antworten Zitat
Blup

Registriert seit: 7. Aug 2008
Ort: Brandenburg
1.429 Beiträge
 
Delphi 10.4 Sydney
 
#32

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 13:12
Fragt sich was das für ein Cache ist? Wenn ich folgendes Fragment vorschalte, in dem ich die Daten komplett einlese, wird das Verarbeiten danach wesentlich schneller:
Delphi-Quellcode:
  for i := Low(AFiles) to High(AFiles) do
  begin
    Watch.Start;
    fs := TFileStream.Create(AFiles[i], fmExclusive);
    SetLength(Buffer, fs.Size);
    fs.ReadBuffer(Buffer[0], fs.Size);
    Watch.Stop;
    fs.Free;
  end;
Diese Funktion braucht für 5.000 frisch erzeugte Dateien zwischen 500-1500 ms.

Wenn ich dann die Daten nochmals in Stringlisten einlese, werden 605-615 ms verbraucht.

Starte ich das Einlesen in die Stringlisten ohne den Vorlauf, braucht das beim ersten Mal 12000-13000 ms.

Vorlauf1500
Verarbeitung615
Summe2115
Direkte Verarbeitung13000

D.h. dieses Verfahren ist 6x schneller!
Ich musste ein par Sachen anders lösen um das Programm mit Delphi 2007 zum Laufen zu bringen.
Die von dir gemessenen Ergebnisse kann ich aber überhaupt nicht nachvollziehen:
Code:
CreateDataClick
         CreateFiles 0:00:14.527
ReadClick
            GetFiles 0:00:00.007
           ReadFiles 0:00:01.692
               Split 0:00:03.112

CreateDataClick
         CreateFiles 0:00:09.681
OpenClick
            GetFiles 0:00:00.006
                Open 0:00:02.614
ReadClick
            GetFiles 0:00:00.006
           ReadFiles 0:00:01.649
               Split 0:00:03.336
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#33

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 13:34
Wenn das OK, dann mit etwas Hirnschmalz ein eigenes "GetLine" geschrieben(einfach per BYTE Pointer durch den Rambuffer nach "CR" suchen und wenn CR gefunden es durch "NULL" ersetzen und die nun "NullTerminierte" Line ab vorherigem Pointer(bzw. anfangs "@0") weiter auswerten.
Und was machst Du mit "dies sind[CRLF]zwei zeilen"?
Nach Deiner Methode mußt Du jede erstellte Zeile überprüfen ob sie vollständig ist, da doch lieber gleich richtig.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Der schöne Günther

Registriert seit: 6. Mär 2013
6.093 Beiträge
 
Delphi 10 Seattle Enterprise
 
#34

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 14:08
Doch, also bei mir ist es ähnlich:

Code:
openClick
GetFiles 50269 ticks, 16 ms
Open 745099 ticks, 238 ms


readClick
GetFiles 90555 ticks, 29 ms
ReadFiles 3411398 ticks, 1094 ms
Split 15388554 ticks, 4935 ms

stringListRead 3179206 ticks, 1019 ms
stringListRead ist jetzt einfach nur ein TStringList-LoadFromFile, also im Endeffekt praktisch das gleiche wie ReadFiles nur mit einem leicht anderen FileMode zum Öffnen der Dateien.

Jetzt das Wichtige: Wir übersehen bei diesen Benchmarks hier alle den Windows-Cache hinter den Kulissen! Ich war grade auch verdutzt über meine Zeiten: Wie kam ich denn auf 45 Sekunden?

Dann habe ich mit RAMMap einmal den Windows-Datei-Cache geleert und statt ca. einer Sekunde zum Lesen bin ich nun wieder bei locker 30 Sekunden. Nur für das Lesen der Dateien.

Um aussagekräftige Messungen zu machen sollte man wohl vor jedem Durchgang einmal komplett den Windows File Cache leeren. Das werde ich im Verlauf des Tages auch nochmal machen...



Auf jeden Fall vielen Dank für die rege Teilnahme an alle!
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#35

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 14:57
...(einfach per BYTE Pointer durch den Rambuffer nach "CR" suchen und wenn CR gefunden es durch "NULL" ersetzen und die nun "NullTerminierte" ...
...da doch lieber gleich richtig....
Für das schnelle Lesen von CSV-Dateien gibt es hier doch eine schöne Lösung. Die kommt mit allen möglichen Sonderspezialfällen klar und ist zudem noch sehr schnell. Nur die Datei *einlesen* muss sie auch und da führt kein Weg dran vorbei.
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

Registriert seit: 18. Mär 2004
Ort: Luxembourg
3.487 Beiträge
 
Delphi 7 Enterprise
 
#36

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 16:48
Die Antwort ist 134217728

Delphi-Quellcode:
procedure TForm1.btnOpenLowLevelClick(Sender: TObject);
var
  AFiles : TStringDynArray;
  fh : THandle;
  fl, fr : LongWord;
  i : integer;
  Buffer : Pointer;
begin
  Watch.Start;
  AFiles := TDirectory.GetFiles(FDir);
  Watch.Stop;
  Prot('GetFiles', Watch);
  Watch.Reset;
  for i := Low(AFiles) to High(AFiles) do
  begin
    Watch.Start;
    fh := CreateFile(PChar(AFiles[i]), GENERIC_READ,
      FILE_SHARE_READ, nil, OPEN_EXISTING,
      FILE_ATTRIBUTE_NORMAL or FILE_FLAG_SEQUENTIAL_SCAN, 0); // Optimiert für nur vorwärts lesen
    fl := GetFileSize(fh, nil);
    fr := 0;
    GetMem(Buffer, fl);
    ZeroMemory(Buffer, fl);
    ReadFile(fh, Buffer^, fl, fr, nil);
    CloseHandle(fh);
    FreeMem(Buffer);
    Watch.Stop;
  end;
  Prot('Lowlevel open', Watch);
  Watch.Reset;
end;
Damit liest er die 5000 Dateien in 160-400 ms komplett ein, auch wenn diese gerade frisch erzeugt wurden.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.017 Beiträge
 
Delphi 12 Athens
 
#37

AW: Viele Dateien performant einlesen

  Alt 30. Apr 2014, 16:52
Zitat:
auch wenn diese gerade frisch erzeugt wurden.
Gerade da liegen die ja vermutlich immernoch im Cache.

Zitat:
Optimiert für nur vorwärts lesen
Zum Glück hatte ich das nicht gleich am Anfang erwähnt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Themen-Optionen Thema durchsuchen
Thema durchsuchen:

Erweiterte Suche
Ansicht

Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 15:21 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz