![]() |
Zeitoptimierung bei Stringzusammensetzung
Hallo liebe Delphi-Gemeinde,
ich bin ganz neu im Forum. Grund dafür ist ein Test, den ich durchgeführt habe und zu einer erschreckenden Erkenntnis kam. :o Es geht um die Umwandlung von Hex-Zahlen in Strings; Der vereinfachte Code:
Delphi-Quellcode:
In einer 300.000er Schleife wird immer wieder aus den Werten AB der HexCode gebildet und in ein Char umgewandelt.
procedure TForm1.Button1Click(Sender: TObject);
var i, j : integer; st, st2, st3 : String; c, n1, n2 : TLargeInteger; begin QueryPerformanceFrequency(c); QueryPerformanceCounter(n1); j := 3; st := 'AB'; st2 := ''; for i := 1 to 300000 do begin if st[1] in ['0'..'9', 'A'..'F'] then begin St2 := St2 + Char(StrToInt('$' + st[1] + st[2])); inc(j, 1); end; end; QueryPerformanceCounter(n2); Showmessage(format('Zeit: %g', [(n2 - n1)/c])); end; Die benötigte Zeit war bei mir 0.3 Sekunden. Erhöhe ich die Schleife um den Faktor 10 erhöht sich aber meine Zeit um das 70 fache, auf 21 Sekunden!!! :shock: Es scheint irgendwie am String zu liegen. Je größer er wird, umso langsamer wird die Zusammensetzung. Also kam mir die Idee, den String st2 nach 100.000 Durchgängen an einen neuen zu übergeben und dann zu leeren.
Delphi-Quellcode:
Schwupps, und es waren nur noch 8 Sekunden, statt 21 !!!
procedure TForm1.Button1Click(Sender: TObject);
var i, j : integer; st, st2, st3 : String; c, n1, n2 : TLargeInteger; begin QueryPerformanceFrequency(c); QueryPerformanceCounter(n1); j := 3; st := 'AB'; st2 := ''; st3 := ''; for i := 1 to 3000000 do begin if st[1] in ['0'..'9', 'A'..'F'] then begin St2 := St2 + Char(StrToInt('$' + st[1] + st[2])); inc(j, 1); end; if Length(St2) > 100000 then begin St3 := St3 +St2; St2 := ''; end; end; St3 := St3 +St2; QueryPerformanceCounter(n2); Showmessage(format('Zeit: %g', [(n2 - n1)/c])); end; Gibt es eine bessere, elegantere Lösung? Am Ende benötige ich jedoch eine Ausgabe im Stringformnat. Besten Dank schon im voraus, für jeden Hinweis. |
Re: Zeitoptimierung bei Stringzusammensetzung
|
Re: Zeitoptimierung bei Stringzusammensetzung
das ganze liegt daran das die länge des Strings ständig verändert wird und somit immer wieder speicher dafür angefordert wird. Schneller ist es einmal mit "SetLength" die Länge des Strings zu setzen und dann mit move den Hex-Wert an die entsprechende Stelle im speicher(String) kopieren.
|
Re: Zeitoptimierung bei Stringzusammensetzung
Wow,
erst einmal besten Dank für die schnelle Antwort. @DGL-luke: Naja, war knapp am eigentlichen Problem vorbei :) @SirThornberry: :arrow: Dein Tipp hat es gebracht! Damit konnte ich die 3.000.000er Schleife auf 1.8 Sekunden drücken, ohne den Stirng aufteilen zu müssen. Besten Dank. Weiter so. Werde öfter mal hier vorbeischauen. Hier kann man noch etwas lernen :idea: |
Re: Zeitoptimierung bei Stringzusammensetzung
dürfte denn sie allgemeinheit noch erfahren wie es gemacht wurde?
liege ich mit folgender Vermutung richtig?
Delphi-Quellcode:
j := 3;
st := 'AB'; SetLength(St2,300000); for i := 1 to Length(St2) do begin if st[1] in ['0'..'9', 'A'..'F'] then begin St2[i]:=Char(StrToInt('$' + st[1] + st[2])); inc(j, 1); end; end; |
Re: Zeitoptimierung bei Stringzusammensetzung
Natürlich darf die Allgemeinheit das erfahren ;-)
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var i, j : integer; st, sx: String; c, n1, n2 : TLargeInteger; begin QueryPerformanceFrequency(c); QueryPerformanceCounter(n1); st := 'AB'; sx := ''; st2 := ''; SetLength(st2, 3000000); // neu for i := 1 to 3000000 do begin if st[1] in ['0'..'9', 'A'..'F'] then begin sx := Char(StrToInt('$' + st[1] + st[2])); // neu move(sx[1], st2[i], Length(sx)+1); // neu end; end; SetLength(st2, Length(PChar(st2))); // etwaige NULL Strings abschneiden QueryPerformanceCounter(n2); Showmessage(format('Zeit: %g', [(n2 - n1)/c])); Showmessage(IntToStr(Length(st2))); |
Re: Zeitoptimierung bei Stringzusammensetzung
Oh Gott, mach das Move weg!
Alt:
Delphi-Quellcode:
Neu:
begin
sx := Char(StrToInt('$' + st[1] + st[2])); // neu move(sx[1], st2[i], Length(sx)+1); // neu end;
Delphi-Quellcode:
begin
st2[i] := Chr(StrToInt('$' + st[1] + st[2])); end; |
Re: Zeitoptimierung bei Stringzusammensetzung
Mensch, dass wird ja immer besser :-D
Die Routine braucht nun statt der anfänglichen 22 Sekunden über 1.8 Sekunden nur noch 1.1 Sekunden!!! Gibt es hier im Forum eigentlich einen Thread mit zeitkritischen Optimierungen, wo noch mehr solche Kniffe zu finden sind? |
Re: Zeitoptimierung bei Stringzusammensetzung
So, jetzt noch:
Delphi-Quellcode:
anstatt
j := Ord (st[1]); if j>57 then dec (j, 65) else dec(j,48);
k := Ord (st[2]); if j>57 then dec (k, 65) else dec(k,48); st2[i] := Char (j shl 4 or k);
Delphi-Quellcode:
und dann wird das auch was :mrgreen: (Bei mir von 1.39 auf 0.18 Sekunden)
st2[i] := Char(StrToInt('$' + st[1] + st[2]));
|
Re: Zeitoptimierung bei Stringzusammensetzung
Megamäßig! Ich verstehe das mit dem shl (links shiften) zwar nicht wirklich ;-)
Aber es bringt bei mir Zeiten zwischen 0.055 und 0.062! Und wenn man jetzt
Delphi-Quellcode:
lieber
j := Ord (st[1]); if j>57 then dec (j, 65) else dec(j,48);
k := Ord (st[2]); if j>57 then dec (k, 65) else dec(k,48);
Delphi-Quellcode:
schreibt, komme ich auf Zeiten zwischen 0.038 und 0.042! j := Ord (st[1]); if j>57 then j := j-65 else j:=j-48; k := Ord (st[2]); if k>57 then k := k-65 else k:=k-48; Dec und Inc scheinen langsamer zu sein als die herkömmlich Art zu Addieren/Subtrahieren. |
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:37 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