Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Frage zum Aneinanderhängen von Strings (https://www.delphipraxis.net/148475-frage-zum-aneinanderhaengen-von-strings.html)

Neutral General 2. Mär 2010 21:33


Frage zum Aneinanderhängen von Strings
 
Hallo,

Die Stringkonkatenation ist ja denke ich mal nicht gerade das schnellste. Vor allem wenn ich einen ganzen Text z.B. Char für Char aneinanderhänge muss jedesmal Speicher für 1 weiteren Char angefordert werden...

Wenn ich jetzt die Länge eines Strings mit SetLength auf sagen wir 200 stelle und somit auch schon mal dementsprechend viel Speicherplatz auf einen Rutsch anfordere und dann wieder schreibe S := S + 'A'; (z.B.).. Wird dann wieder Speicher angefordert oder geht das dann performanter weil noch genug verfügbar ist?


Also konkret:

Delphi-Quellcode:
var Str1, Str2: String;
begin
  // Str1
  Str1 := '';
  for i:= 1 to 100000 do
    Str1 := Str1 + 'A';
 
  // Str2
  SetLength(Str2,100000);
  FillChar(Str2[1],100000,0);
  for i:= 1 to 100000 do
    Str2 := Str2 + 'A';
:arrow: Welche der beiden Schleifen ist schneller?

Gruß
Neutral General

Christian Seehase 2. Mär 2010 21:57

Re: Frage zum Aneinanderhängen von Strings
 
Die Schleifen dürften gleichschnell sein, denn bei der zweiten wird auch immer Zeichen für Zeichen angefügt, nur dass der zweite String anschliessend 200000 Zeichen lang ist.
Schneller geht es, wenn Du die Zeichen in den jeweiligen Index schreibst:

Delphi-Quellcode:
  SetLength(Str2,100000);
  for i:= 1 to 100000 do
    Str2[i] := 'A';

Neutral General 2. Mär 2010 22:06

Re: Frage zum Aneinanderhängen von Strings
 
Oh.. richtig.. jetzt wo du's sagst :stupid:

Jo danke ;) Ich denke dann hätte sich das auch erledigt :mrgreen:

s.h.a.r.k 2. Mär 2010 22:44

Re: Frage zum Aneinanderhängen von Strings
 
Vielleicht wäre es an der Stelle auch noch interessant zu wissen, was denn in einem String steht, wenn ich SetLength auf ihn anwende, also sowas hier
Delphi-Quellcode:
var
  str : String;
begin
  SetLength(set, 100);
  // <- was hat str nun für einen Wert?
end;

himitsu 3. Mär 2010 06:40

Re: Frage zum Aneinanderhängen von Strings
 
Da SetLength den Speicher nicht initialisiert, sind alle neuen Zeichen undefiniert.

Wurde zufällig ein ein neuer/leerer Speicherbereich verwendet, dann stehen #0-en drin, ansonsten halt irgendwelche zufällig dort im Speicher rumliegende Byte-/Zeichenfolgen.

alzaimar 3. Mär 2010 06:43

Re: Frage zum Aneinanderhängen von Strings
 
Ausprobieren? F1 drücken?

Und folgende Stringkonkatenation ist noch schneller:
Delphi-Quellcode:
C := Str1 + Str2;
:stupid:
Das ist ca. 10x schneller als die Variante, die erst per SetLength den gesammten Speicher reserviert, welche widerum 10x schneller als die Variante ist, die den String Zeichen für Zeichen zusammenbappt.

Ich habe das übrigens einfach ausprobiert, das hat mich 5 min gekostet und die Frage war beantwortet.

Zitat:

Zitat von himitsu
Da SetLength den Speicher nicht initialisiert, sind alle neuen Zeichen undefiniert.

Korrekt, gilt aber nur für Strings, nicht für Arrays o.ä. Aber hier geht es ja (nur) um Strings und von daher ... blafasel blub.
Das hätte man übrigens auch durch Verwendung des magischen EffEins ermitteln können.

himitsu 3. Mär 2010 07:12

Re: Frage zum Aneinanderhängen von Strings
 
Zitat:

Zitat von Neutral General
Also konkret:

Delphi-Quellcode:
var Str1, Str2: String;
begin
  // Str1
  Str1 := '';
  for i:= 1 to 100000 do
    Str1 := Str1 + 'A';
 
  // Str2
  SetLength(Str2,100000);
  FillChar(Str2[1],100000,0);
  for i:= 1 to 100000 do
    Str2 := Str2 + 'A';

Du meintest wohl
Delphi-Quellcode:
// Str2
SetLength(Str2, 100000);
//FillChar(Str2[1], 100000 * SizeOf(Char), 0);
for i := 1 to 100000 do
  Str2[i] := 'A';
Denn sonst ist die 2 noch langsamer, da sie schon mit einem größerem Ausgangsstring genau das Selbe (in Bezug auf die Schleife) macht.

Delphi-Quellcode:
Var P: PChar;

// Str2
SetLength(Str2, 100000);
P := @Str[1];
for i := 99999 downto 0 do
  P[i] := 'A';
Dank 'ner guten Codeoptimierung seitens des Delphicompilers ist dieses mit das Schnellste.

Schneller ist da nur noch dieses (vorallem seit D2006?, wo das FastCodeProjekt in Delphi integriert wurde)
Delphi-Quellcode:
// Str2 = AnsiString
SetLength(Str2, 100000);
FillChar(@Str2[1], 100000, 'A');
oder gleich Delphi-Referenz durchsuchenStringOfChar
Delphi-Quellcode:
Str2 := StringOfChar('A', 100000);

Dieses
Delphi-Quellcode:
Str1 := '';
for i:= 1 to 100000 do
  Str1 := Str1 + 'A';
enspricht ja
Code:
Str1 leeren (falls noch nicht leer)
Schleife mit 100.000 Durchgängen
  neuen String mit Länge ( Length(Str1) + Length('A') ) reservieren
  beide Strings in den neuen String reinkopieren
  alten String Str1 freigeben
  Variable Str1 durch neuen String ersetzen.
Ende der Schleife

Neutral General 3. Mär 2010 08:45

Re: Frage zum Aneinanderhängen von Strings
 
Hallo,

Vielleicht hätte ich erwähnen sollen, dass es um das Scannen von Quellcode geht. Und da muss ich eben nunmal Zeichen für Zeichen durch den String geben und wenn ich auf einen String treffe muss ich dann auch immer Zeichen für Zeichen schauen ob das nächste Zeichen noch zu dem String gehört und ggf. zum Token hinzufügen.

Von daher nutzt mir

Delphi-Quellcode:
FillChar(Str,10000,'A');
o.ä. nichts :mrgreen:

himitsu 3. Mär 2010 08:51

Re: Frage zum Aneinanderhängen von Strings
 
Besser als
Delphi-Quellcode:
S := S + irgendwas;
ist dann halt
Delphi-Quellcode:
//Insert(irgendwas, S, Length(S) + 1);
Insert(irgendwas, S, MaxInt);
Denn wenn Insert, bzw. der Speichermanager den internen Speicher hier "inplace", also ohne verschieben/umkopieren vergrößern kann, dann wird nur noch der anzuhängende String da reinkopiert und fertig.

Zitat:

S := S1 + S2;
Ich hab allerdings nicht nachgeschaut, ob Concat2 (_LStrCat, bzw. _UStrCat) vielleicht prüft, ob S1 und S das Selbe sind und hier auch schon in dieser Art optimiert optimiert.

Khabarakh 3. Mär 2010 15:57

Re: Frage zum Aneinanderhängen von Strings
 
Zitat:

Zitat von Neutral General
Vielleicht hätte ich erwähnen sollen, dass es um das Scannen von Quellcode geht. Und da muss ich eben nunmal Zeichen für Zeichen durch den String geben und wenn ich auf einen String treffe muss ich dann auch immer Zeichen für Zeichen schauen ob das nächste Zeichen noch zu dem String gehört und ggf. zum Token hinzufügen.

Äh, wozu dann überhaupt Strings erzeugen :stupid: ? Bau dir ein TSubstring, also einen Record (Parent, Start, Length), der einfach ein Intervall in einem Parent-String referenziert. Schon bist du allokationsfrei ;) .


Alle Zeitangaben in WEZ +1. Es ist jetzt 00:57 Uhr.

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