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 3 von 4     123 4   
Dejan Vu
(Gast)

n/a Beiträge
 
#21

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 10:43
ca. 120 MB? LOL ist doch heute nix mehr...
Blockread direkt ins Ram aller Dateien und dann verarbeiten?
Es handelt sich um 5000 Dateien, die dann auch 5000 -lol- Mal per Blockread eingelesen werden müssen. Das geht dann auch nicht schneller als 'LoadFromFile'.

Imho kann man höchstens die Tatsache ausnutzen, das es sich um eine SSD handelt und die Dateien wirklich über mehrere Threads einlesen. Die Directory ist ja schnell gelesen und so ein Thread zum einlesen ist auch Einsfixdrei gebaut. Dann kann man doch einfach prüfen, ob es was bringt...
  Mit Zitat antworten Zitat
Blup

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

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 10:50
Fass die z.B. 5000 Dateien zu einer zusammen, die im ersten Schritt importiert wird.
Dann muss man die Dateien aber auch alle einlesen. Und wenn man sie schon mal eingelesen hat, kann man sie auch gleich verarbeiten
Nicht unbedingt, das hängt vom Anwendungsfall ab. Bei einem einmaligen Import wäre die Zeit dafür sicher nicht das Thema.

Wir hatten den Fall, der Katalog eines Herstellers besteht aus mehr als 1000 kleinen Dateien, die die täglichen Änderungen der Stammdaten enthalten und ständig erweitert werden. Unser Testsystem importiert alle Änderungen und wir erstellen ca. einmal im Jahr oder bei Bedarf eine große Datei. Wenn unsere Kunden diesen Katalog benötigen, wird bei der Installation sehr viel Zeit gespart. Neben der großen Datei müssen nur die nachfolgenden Änderungen importiert werden.
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#23

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 10:51
Bei diesem Ansatz kann man durch einen Thread etwas mehr herausholen.

Einer Klasse wird der Dateiname übergeben. Diese Klasse hat eine Eigenschaft, die diese Datei als TStringList (oder TStrings) zur Verfügung stellt. Allerdings wird beim Zugriff auf diese Eigenschaft erst der Inhalt der Datei geladen (wenn dies in der Zwischenzeit noch nicht erfolgt ist).

Wenn sich nun jede Instanz an einen Thread hängt, der das Laden der Dateien in den Instanzen bewirkt, dann kann die Verarbeitung und das Laden der Datei in unterschiedlichen Threads erfolgen und die Zeit reduziert sich im optimalen Fall auf die reine Ladezeit / Verarbeitungszeit der Dateien (je nachdem, was länger dauert).

Wenn das reine Laden 30 Sekunden dauert und die Verarbeitung 15 Sekunden, dann kann das gesamte Laufzeitverhalten bis auf 30 Sekunden reduziert werden.

Das geht natürlich nur, wenn die Verarbeitung keine Festplatten-Aktionen erfordert, denn dadurch wird ja die Ressource Festplatte wieder eingebunden.

UPDATE

Wenn die reine Verarbeitung nur einen Bruchteil der gesamten Abarbeitung beansprucht, wird dieses Konstrukt aber uninteressant und schafft nur eine weitere Komplikation
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)

Geändert von Sir Rufo (29. Apr 2014 um 10:56 Uhr)
  Mit Zitat antworten Zitat
Dejan Vu
(Gast)

n/a Beiträge
 
#24

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 11:51
Wenn die reine Verarbeitung nur einen Bruchteil der gesamten Abarbeitung beansprucht, wird dieses Konstrukt aber uninteressant und schafft nur eine weitere Komplikation
Genau, außer vielleicht bei einer SSD oder einer Platte mit mehreren Leseköpfen. Da könnte es etwas bringen.
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

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

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 12:38
... oder einer Platte mit mehreren Leseköpfen. Da könnte es etwas bringen.
Möglich aber unwahrscheinlich, da dann auch die Verwaltungsinformation "in der Nähe" der Daten liegen müßte. (alle Daten auf einem Zylinder)

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

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

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 12:53
Letztendlich sind das alles Ratespiele. Warum nicht zielgerichtet vorgehen und einen Profiler einsetzen. Dann die Teile mit dem größten Einfluss auf die Performance optimieren, indem man z.b. Das Encoding selber setzt anstatt das die Stringliste selber machen zu lassen usw.
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all
  Mit Zitat antworten Zitat
Benutzerbild von Sir Rufo
Sir Rufo

Registriert seit: 5. Jan 2005
Ort: Stadthagen
9.454 Beiträge
 
Delphi 10 Seattle Enterprise
 
#27

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 16:09
Letztendlich sind das alles Ratespiele. Warum nicht zielgerichtet vorgehen und einen Profiler einsetzen. Dann die Teile mit dem größten Einfluss auf die Performance optimieren, indem man z.b. Das Encoding selber setzt anstatt das die Stringliste selber machen zu lassen usw.
Hat er doch schon gemacht (siehe ersten Beitrag) aber nicht explizit aufgeschlüsselt, wieviel Zeit jeder Schritt beansprucht.

Mit der OmniThreadLibraray könnte man sich auch eine Pipeline bauen, wo Einlesen und Verarbeiten separate Schritte sind. Dann kann man darauf weiter aufbauen und jeden Schritt nochmals in sich optimieren.
Kaum macht man's richtig - schon funktioniert's
Zertifikat: Sir Rufo (Fingerprint: ‎ea 0a 4c 14 0d b6 3a a4 c1 c5 b9 dc 90 9d f0 e9 de 13 da 60)
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

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

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 17:28
Ja, aber er hat LoadFromFile nicht profiled. Wenn man das echt instrumentieren will, muß man notfalls eine Kopie davon machen, an der man profiled und optimiert. Zum Schluß hat man dann automatisch eine "Ladeoptimierte" TStringList.
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.016 Beiträge
 
Delphi 12 Athens
 
#29

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 21:01
Da es aber schnell genug läuft, wenn die Dateien schon im Cache liegen, dann ist das Encoding der TStringList vernachlässigbar.

Ansonsten hatte ich ja eigentlich schon alles erklärt.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von Union
Union

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

AW: Viele Dateien performant einlesen

  Alt 29. Apr 2014, 21:31
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!

Komplettes Testprogramm:
Delphi-Quellcode:
unit main;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls, System.Diagnostics;

type
  TForm1 = class(TForm)
    btnCreateData: TButton;
    btnRead: TButton;
    MemoProt: TMemo;
    btnOpen: TButton;
    procedure btnCreateDataClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure btnReadClick(Sender: TObject);
    procedure btnOpenClick(Sender: TObject);
  private
    { Private-Deklarationen }
    FDir : string;
    FWatch : TStopWatch;
    procedure Prot(const AMessage : string; AWatch : TStopWatch);
  public
    { Public-Deklarationen }
    property Watch : TStopWatch read FWatch;
  end;

var
  Form1: TForm1;

implementation

uses
  System.Types,
  System.IOUtils,
  System.StrUtils;

{$R *.dfm}

procedure TForm1.btnCreateDataClick(Sender: TObject);
var
  i : integer;
  Line : string;
begin
  Watch.Start;
  Line := Dupestring('ABCDEFGHI;', 2400);
  for i := 1 to 5000 do
    TFile.WriteAllText(TPath.Combine(FDir, Format('%4.4d.txt', [i])), Line);
  Watch.Stop;
  Prot('CreateFiles', Watch);
  Watch.Reset;
end;

procedure TForm1.btnOpenClick(Sender: TObject);
var
  AFiles : TStringDynArray;
  fs : TFileStream;
  i : integer;
  Buffer : TByteDynArray;
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;
    fs := TFileStream.Create(AFiles[i], fmExclusive);
    SetLength(Buffer, fs.Size);
    fs.ReadBuffer(Buffer[0], fs.Size);
    Watch.Stop;
    fs.Free;
  end;
  Prot('Open', Watch);
  Watch.Reset;
end;

procedure TForm1.btnReadClick(Sender: TObject);
var
  AFiles : TStringDynArray;
  i : integer;
  Line : string;
  sl : TStringList;
  SplitWatch : TStopWatch;
begin
  Watch.Start;
  AFiles := TDirectory.GetFiles(FDir);
  Watch.Stop;
  Prot('GetFiles', Watch);
  Watch.Reset;

  sl := TStringList.Create;
  sl.Delimiter := ';';
  try
    SplitWatch := TStopWatch.Create;
    for i := Low(AFiles) to High(AFiles) do
    begin
      Watch.Start;
      Line := TFile.ReadAllText(AFiles[i]);
      Watch.Stop;
      SplitWatch.Start;
      sl.DelimitedText := Line;
      SplitWatch.Stop;
    end;
    Prot('ReadFiles', Watch);
    Prot('Split', SplitWatch);
  finally
    SplitWatch.Reset;
    Watch.Reset;
    sl.Free;
  end;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FDir := TPath.Combine(TPath.GetDirectoryName(Application.ExeName), 'Data');
  TDirectory.CreateDirectory(FDir);
  FWatch := TStopWatch.Create;
end;

procedure TForm1.Prot(const AMessage : string; AWatch : TStopWatch);
begin
  MemoProt.Lines.Add(AMessage + ' ' +AWatch.ElapsedTicks.ToString+' ticks, '+AWatch.ElapsedMilliseconds.ToString+' ms');
end;
Ibi fas ubi proxima merces
sudo /Developer/Library/uninstall-devtools --mode=all

Geändert von Union (29. Apr 2014 um 21:34 Uhr)
  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 19:08 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