Einzelnen Beitrag anzeigen

Dennis07

Registriert seit: 19. Sep 2011
Ort: Deutschland
482 Beiträge
 
Delphi 11 Alexandria
 
#87

AW: Procedure vs Function, Vor- und Nachteile

  Alt 21. Apr 2018, 23:53
Moin moin zum Benchen hab ich für andere Beispiele das GetTick von Agner Fog genommen. Es kommt kein Zeitwert raus aber ein Wert mit dem man arbeiten kann. Getestet mit VAR OUT CONST hab ich es selbst noch nicht aber bei Bedarf kann ich es Nachreichen.
...was nicht notwendig ist, denn man hat ja immer die GetTickCount-Routine von Windows. Diese ist in der RTL schön gewrappt und abrufbar. Hab mir da so ein schönes stückchen Code gebastelt, das im grunde für fast alles anwendbar ist und mit dem ich für jede beliebige Routine ohne viel Anpassarbeit immer die Performance Ablesen kann. Das, auf diesen Fall zugeschnitten, sieht bei mir dann so aus:

Delphi-Quellcode:
const
  amount = 1000000;
  attempts = 50;
var
  x,y: cardinal;
  tickstart, tickfinish: cardinal;
  allcounts: cardinal; s: String;
begin
  allcounts := 0;
  for x := 1 to attempts do
  begin
    y := 1;
    tickstart := GetTickCount;
    while y <= amount do
    begin
      Randomize;
      SetLength(s, Random(255));
      //entw Foo(s);
      //oder FooC(s);
      //oder FooV(s);
      inc(y);
    end;
    tickfinish := GetTickCount;
    allcounts := allcounts + tickfinish - tickstart;
  end;
  showmessage(inttostr((allcounts div attempts)));
end;
Ja, ich weiß, Code qualität und Formatierung zum Kotzen, aber darauf kommt es hier idF mal nicht an.
Was hier geschieht, kurz und Knackig: Es wird eine der drei Routinen 1000000 mal hintereinander aufgerufen und von diesen Aufrufen die insgesamte Zeit (Ticks) gemessen. Das ganze wird 50 mal ausgeführt, und das Endergebnis am Ende durch 50 geteilt. So hat man einen Durchschnittswert, der auf 50 Versuchen basiert, und die Zeit für 1000000 Aufrufe widergibt. Der String besitzt immer eine Zufallslänge zwischen 0 und 255, die vor jedem Funktionsaufruf neu ausgewürfelt wird.

Die Testroutinen waren für die Erste Versuchsreihe wie folgt deklariert:

Delphi-Quellcode:
procedure Foo(S: String);
begin

end;

procedure FooC(const S: String);
begin

end;

procedure FooV(var S: String);
begin

end;
Die Ergebnisse waren beeindruckend, wenn man es so beschreiben will:
  • Für Foo(s): 77 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooC(s): 48 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooV(s): 48 Ticks je 1000000 Aufrufe im Schnitt

Nun habe ich Statt Unicode- Ansi-Strings genommen. Der Benchmark lief wie folgt ab:
  • Für Foo(s): 74 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooC(s): 50 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooV(s): 50 Ticks je 1000000 Aufrufe im Schnitt

Bei ShortString, so dachte ich mir, könne man sogar noch mehr Performance herausholen. So testete ich dies ebenfalls:
  • Für Foo(s): 64 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooC(s): 39 Ticks je 1000000 Aufrufe im Schnitt
  • Für FooV(s): 39 Ticks je 1000000 Aufrufe im Schnitt

Es scheint, als dass in den meisten Fällen, die bei zufälligen Stringlängen generiert wurden, "const" und "var" sich identisch verhalten, oder zumindest eine identische Performance besitzen. Hervorstechen tut ganz klar Foo, und zwar im negativen Sinne.

Im allgemeinen kann man grob geschätzt sagen, dass sich mit "const" die Performance bei UnicodeStrings (um 37,7%), bei AnsiStrings (um 32,4%), sowie bei ShortStrings (um 39,1%) steigern lässt. Verallgemeinert lässt sich hier eine Tendenz von etwas über einem Drittel im Schnitt feststellen. Zwischen "var" und "const" konnte in dieser Testreihe kein merklicher Unterschied festgestellt werden. Ich gehe davon aus, dass dies nur bei genauerer bestrachtungsweise der String-Länge passieren kann. Darauf, das zu überprüfen, habe ich aber im Augenblick leider keinen Bock, weshalb die Fragestellung hier offen bleibt. Evtl kann ja jemand anderes hier aushelfen...?
Dennis

Geändert von Dennis07 (21. Apr 2018 um 23:57 Uhr)
  Mit Zitat antworten Zitat