![]() |
Delphi-Version: 2006
getters sind langsam
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:
Ergebnis:
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; 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 |
AW: getters sind langsam
bischen OT, aber hast Du schon mal inline probiert?
![]() Ansonsten ist mir dein Beispiel zu sehr entgegen meinen Gewohnheiten (Leerzeilen, zu kurze Namen), als dass ich das innerhalb nützlicher Frist genau verstehen würde was du da machst. |
AW: getters sind langsam
Zitat:
Entschuldigt, falls meine Nomenklatur komplett gegen den Standard ist! Und bitte nicht von der gvProfiler - Variable verwirren lassen. Die verwaltet nur getTickCounts. Da das nichts mit dem Problem zu tun hat, hab ich den Code nicht aufgeführt. |
AW: getters sind langsam
Du testet mit High(Integer)-1. Also rund 4,29 Milliarden mal.
Ist das später auch eine Größenordnung die ein Standardfall darstellt? Oder reden wir dann eher von 1000 bis 1000000 Schleifendurchläufen? |
AW: getters sind langsam
Zitat:
|
AW: getters sind langsam
Zitat:
In Assember-Form sieht das ungefähr so aus: Variante 1
Code:
Variante 2
MOV EAX, [interface.getval] // Funktionsadresse ins Register EAX laden
CALL EAX // Springe zur Adresse im Register EAX
Code:
Möglich, dass der echte Assember-Code etwas anders aussieht, aber das Prinzip sollte klar werden.
CALL toInd
|
AW: getters sind langsam
Zitat:
Delphi-Quellcode:
) werden das
virtual
Delphi-Quellcode:
leider ziemlich sicher ignorieren. Das beißt sich mit dem Konzept der VMT (Virtual Method Table). Sollte einleuchten, wenn man sich Namenlosers Erklärung dazu durchliest.
inline
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:02 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz