Einzelnen Beitrag anzeigen

Alex_ITA01

Registriert seit: 22. Sep 2003
1.115 Beiträge
 
Delphi 12 Athens
 
#1

Generic List, große Liste, große Datenstruktur, Geschwindigkeit

  Alt 21. Aug 2015, 08:45
Hallo zusammen,
ich habe mal meinen originalen Quelltext angepasst um folgendes Beispiel zu posten (deswegen bitte über Variablennamen und Sinnlosigkeit des Quelltextes nicht äußern, mir geht es um das eigentliche Problem):

Delphi-Quellcode:
unit Unit1;

interface

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

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;

type
  TMyNextData8 = packed record
  const
    Ident = 'TMyNextData8';
  public
    a : String[18];
    b : Word;
    c : Word;
  end;

  TMyNextData7 = packed record
  private
  public
    ItemCount: Integer;
    Items : Array[00..09] of TMyNextData8;
  end;

type
  TMyNextData6 = packed record
  const
    Ident = 'TMyNextData6';
  public
    a : LongWord;
    b : String[18];
    c : String[40];
    d : Double;
    e : String[03];
    f : String[04];
    g : String[01];
    h : String[10];
    i : String[01];

    j : LongWord;
    k : String[12];
    l : String[08];
  end;

  TMyNextData5 = packed record
  private
  public
    ItemCount: Integer;
    Items : Array[0..09] of TMyNextData6;
  end;

type
  TMyNextData4 = packed record
  const
    Ident = 'TMyNextData4';
  public
    a: Word;
    b : LongWord;
    c : String[12];
    d : String[12];
    e : String[12];
    f : String[08];
    g : String[10];
    h : LongWord;
  end;

type
  TMyNextData3 = packed record
  const
    MaxAnz = 10;
  private
  public
    ItemCount: Integer;
    Items : Array[00..MaxAnz-1] of TMyNextData4;
  end;

type
  TMyNextData = packed record
  const
    MyStr = 'TMyNextData';
  public
    a : String[16];

    b : TDate;
    c : TTime;
    d : LongWord;

    e : LongWord;
    f : String[12];
    g : String[12];
    h : String[12];
    i : TMyNextData3;

    j : String[06];
    k : String[18];
    l : String[40];
    m : Double;
    n : String[03];
    o : String[04];
    p : String[10];
    q : TMyNextData5;

    r : LongWord;
    s : String[12];

    t : String[08];
    u : String[08];

    v : String[04];
    w : TDate;
    x : String[10];

    y : String[10];
    z : String[01];
    aa : String[01];
    bb : String[10];

    cc : TMyNextData7;

    dd : Array[0..49] of Byte;
  end;

type
  TMyData = packed record
  const
    MyStr = 'TMyData';
  public
    ID : LongWord;
    ID2 : LongWord;
    ID3 : LongWord;
    First : Boolean;
    Second : Boolean;
    Third : Boolean;


    a : LongWord;
    b : LongWord;
    c : Byte;
    d : Byte;
    e : Word;
    f : TMyNextData;

    g : Word;
    h : LongWord;
    i : String[10];
    j : String[18];
    k : Byte;
    l : String[1];
    m : String[10];
    n : LongWord;
    o : TDateTime;

    p,
    q,
    r,
    s,
    t,
    u,
    v,
    w,
    x : Word;

    y : String[10];
    z : String[4];

    aa,
    bb : Byte;

    cc : String[8];

    dd : String[01];
    ee : Word;
    ff : Boolean;

    gg,
    hh : Byte;


    ii : Byte;
    jj : LongWord;

    kk : Word;
    ll : Word;
    mm : Word;
    nn : Array[0..93] of Byte;
    oo : TDateTime;


    pp : TDateTime;
    qq : TDateTime;

    procedure Clear;
  end;

type
  TMyListe = class(TList<TMyData>)
  private
  public
    function GetFirstItems(var aFirstList: TMyListe): Integer;
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
var
  AllDataList : TMyListe;
  FirstList : TMyListe;
  i : Integer;
  aData : TMyData;
  aMes1,
  aMes2 : TStopWatch;
begin
  AllDataList := TMyListe.Create;
  FirstList := TMyListe.Create;

  aMes1.Create;
  aMes1.Reset;
  aMes1.Start;

  try
    //5000 Einträge erstellen (First=True)
    for i := 1 to 5000 do
    begin
      aData.Clear;
      aData.ID := i;
      aData.First := True;

      AllDataList.Add(aData);
    end;

    //5000 Einträge erstellen (First=False)
    for i := 1 to 5000 do
    begin
      aData.Clear;
      aData.ID2 := i;
      aData.First := False;

      AllDataList.Add(aData);
    end;

    //Schritt1: Rootliste füllen
    aMes2.Create;
    aMes2.Reset;
    aMes2.Start;
    AllDataList.GetFirstItems(FirstList);
    aMes2.Stop;

  finally
    if Assigned(FirstList) then
    begin
      FirstList.Clear;
      FreeAndNil(FirstList);
    end;

    if Assigned(AllDataList) then
    begin
      AllDataList.Clear;
      FreeAndNil(AllDataList);
    end;
  end;

  aMes1.Stop;
  ShowMessage('Zeitmessung 1 (s): ' +
               IntToStr(Round(aMes1.ElapsedMilliseconds/1000)));

  ShowMessage('Zeitmessung 2 (s): ' +
               IntToStr(Round(aMes2.ElapsedMilliseconds/1000)));
end;

{ TMyListe }

function TMyListe.GetFirstItems(var aFirstList: TMyListe): Integer;
var
  i: Integer;
  tmpData: TMyData;
begin
  if Assigned(aFirstList) then
  begin
    aFirstList.Clear;
    i := 0;
    while i < Self.Count do
    begin
      if (Self.Items[i].First) then
      begin
        tmpData := Self.Items[i];
        Self.Delete(i);
        aFirstList.Add(tmpData);
      end
      else begin
        inc(i);
      end;
    end;
  end;
  Result := aFirstList.Count;
end;

{ TMyData }

procedure TMyData.Clear;
begin
  FillChar(Self, SizeOf(Self), 0);
end;

end.
Ein einfaches Formular, ein Button drauf und die Routine aufrufen.
Die SizeOf meiner "TMyData" Struktur beträgt 2732 Bytes.

Wenn ich jetzt in der AllDataList meine Testeinträge hinzugefügt habe und möchte dann mit der Funktion "GetFirstItems" nur eine bestimmte Anzahl von diesen Einträgen in einer anderen Liste zurück haben, dann dauert es 11Sekunden auf meinen Rechner, bis die Funktion "GetFirstItems" abgearbeitet wurde. Diese Funktion löscht aus der Originalen Liste und added die Einträge in eine separate Liste.

Könnt ihr mir sagen, was man hier anders machen könnte, damit es schneller geht?
Ich denke eine Liste mit 10000 Einträgen, die dann 5000 davon in eine andere Liste hinzufügt und diese 5000 bei sich löscht, kann doch keine 11 Sekunden dauern oder doch?

Viele Grüße

Benutze Win 8.1 mit XE7
Let's fetz sprach der Frosch und sprang in den Mixer
  Mit Zitat antworten Zitat