Delphi-PRAXiS
Seite 1 von 2  1 2      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Delphi Zeitoptimierung bei Stringzusammensetzung (https://www.delphipraxis.net/56808-zeitoptimierung-bei-stringzusammensetzung.html)

amigage 11. Nov 2005 16:15


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:
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;
In einer 300.000er Schleife wird immer wieder aus den Werten AB der HexCode gebildet und in ein Char umgewandelt.
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:
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;
Schwupps, und es waren nur noch 8 Sekunden, statt 21 !!!
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.

DGL-luke 11. Nov 2005 16:19

Re: Zeitoptimierung bei Stringzusammensetzung
 
Wofür diesen Aufwand?

Delphi-Referenz durchsuchenIntToHex

SirThornberry 11. Nov 2005 16:24

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.

amigage 11. Nov 2005 16:34

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:

glkgereon 11. Nov 2005 17:11

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;

amigage 12. Nov 2005 08:28

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)));

Flocke 12. Nov 2005 08:50

Re: Zeitoptimierung bei Stringzusammensetzung
 
Oh Gott, mach das Move weg!

Alt:
Delphi-Quellcode:
   begin
     sx := Char(StrToInt('$' + st[1] + st[2])); // neu
     move(sx[1], st2[i], Length(sx)+1);        // neu  
   end;
Neu:
Delphi-Quellcode:
   begin
     st2[i] := Chr(StrToInt('$' + st[1] + st[2]));
   end;

amigage 12. Nov 2005 09:11

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?

alzaimar 12. Nov 2005 09:23

Re: Zeitoptimierung bei Stringzusammensetzung
 
So, jetzt noch:
Delphi-Quellcode:
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);
anstatt
Delphi-Quellcode:
st2[i] := Char(StrToInt('$' + st[1] + st[2]));
und dann wird das auch was :mrgreen: (Bei mir von 1.39 auf 0.18 Sekunden)

amigage 13. Nov 2005 10:15

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:
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);
lieber
Delphi-Quellcode:
     
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;
schreibt, komme ich auf Zeiten zwischen 0.038 und 0.042!
Dec und Inc scheinen langsamer zu sein als die herkömmlich Art zu Addieren/Subtrahieren.


Alle Zeitangaben in WEZ +1. Es ist jetzt 20:50 Uhr.
Seite 1 von 2  1 2      

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz