Thema: Delphi getters sind langsam

Einzelnen Beitrag anzeigen

dpg123

Registriert seit: 13. Apr 2015
22 Beiträge
 
Turbo Delphi für Win32
 
#1

getters sind langsam

  Alt 18. Dez 2018, 14:05
Delphi-Version: 2006
Hallo zusammen,

für ein Number-Cruncher-Projekt brauche ich einen vernünftigen Kompromiss aus Speed und komfortable Code-Wartung bzw Code-Verwendung für den Zugriff auf ein dynamisches Array.

Einerseits soll der Zugriff möglichst schnell sein, andererseits sollten diverse OO-Prinzipien eingehalten werden.

Mit folgendem Demo-Prog hab ich mal die Zeiten vergleichen:

Delphi-Quellcode:
type

  TForm1 = class(TForm)

    procedure FormCreate(Sender: TObject);

  private
    { Private-Deklarationen }

    function getInd( x: integer; aMin: integer ): Integer;

  public
    { Public-Deklarationen }


  end;


type

  TDynValueArray = array of Extended;

  TStatValueArray = array [20..120] of Extended;


  IDynArray = interface( IInterface )
  ['{4F626337-44B1-4340-A05C-711A04A0DEB4}']

    function getMin(): Integer;

    function getMax(): Integer;

    function getVal( x: integer ): Extended;

    procedure setValue( x: Integer; aValue: Extended );

    property val[ index: integer ]: extended read getVal write setValue; default;

    property min: Integer read getMin;

    property max: Integer read getMax;

  end;


  TDynArrayImpl = class(TInterfacedObject,IDynArray)


    var

        Fval: TDynValueArray;

        Fmin: Integer;

        Fmax: Integer;
        

    function getMin(): Integer;

    function getMax(): Integer;


    function getVal( x: integer ): Extended;

    procedure setValue( x: Integer; aValue: Extended );

    
    constructor Create( aMin: Integer; aMax: Integer );

  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}


constructor TDynArrayImpl.Create(aMin, aMax: Integer);
var
  i: integer;
begin


  self.Fmin := aMin;

  self.Fmax := aMax;


  SetLength(

    Self.Fval,

    self.Fmax - self.Fmin + 1

    );


  for i := 0 to Length( self.Fval )-1 do
    self.Fval[ i ] := 0;

end;

function TDynArrayImpl.getMax: Integer;
begin
  Result := self.Fmax;
end;

function TDynArrayImpl.getMin: Integer;
begin
  Result := self.FMin;
end;

function TDynArrayImpl.getVal(x: integer): Extended;
begin

  result := Self.Fval[ x - self.FMin ];

end;

procedure TDynArrayImpl.setValue(x: Integer; aValue: Extended);
begin

  Self.Fval[ x - self.FMin ] := aValue;

end;


procedure TForm1.FormCreate(Sender: TObject);

var

  i: Integer;

  lF: Extended;

  lDynAr: IDynArray;

  lPid: Integer;

  lMin,lMax,x: Integer;

  lDynValAr: TDynValueArray;

  lValArStat: TStatValueArray;


const

  lcAnzZugriffe = High(Integer);


  function toInd(aX: Integer): Integer;
  begin
    Result := x - lMin;
  end;

begin


  lMin := 20;

  lMax := 120;

  x := 80;


  // Variante 1: dyn Array hinter einem Interface kapseln

  lDynAr := TDynArrayImpl.Create(lMin,lMax);

  lPid := gvProfiler.start();

  for i := 1 to lcAnzZugriffe do
    lF := lDynAr[x];

  gvProfiler.stop(lPid,'interface');



  SetLength(

    lDynValAr,

    lMax - lMin + 1

    );


  // Variante 2: direkter Zugriff auf das dyn Array, Indexverschiebung per function kapseln

  lPid := gvProfiler.start();

  for i := 1 to lcAnzZugriffe do
    lF := lDynValAr[ toInd(x) ];

  gvProfiler.stop(lPid,'dynAr direkt, function offset');


  // Variante 3: direkter Zugriff auf das dyn Array, direkte Indexverschiebung

  lPid := gvProfiler.start();

  for i := 1 to lcAnzZugriffe do
    lF := lDynValAr[ x - lMin ];

  gvProfiler.stop(lPid,'dynAr direkt, offset direkt');


  // Zum Vergleich: statisches Array

  lPid := gvProfiler.start();

  for i := 1 to lcAnzZugriffe do
    lF := lValArStat[ x ];

  gvProfiler.stop(lPid,'statAr direkt, ohne offset');

end;

function TForm1.getInd(x: integer; aMin: integer): Integer;
begin

  Result := x - aMin;

end;
Ergebnis:

Variante1: interface
16832 ms

Variante2: dynAr direkt, function offset
8143 ms

Variante3: dynAr direkt, offset direkt
3822 ms

Vergleich: statAr direkt, ohne offset
3791 ms


Was ich mir nicht erklären kann:

Warum ist der getter-Zugriff des Interfaces (var 1) um Faktor 2 langsamer als die Indexberechung per function (var 2)?

Wie würdet ihr es lösen, wenn zumindest die Indexverschiebung gekapselt sein soll?


Vielen Dank und Grüße
  Mit Zitat antworten Zitat