AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Sonstige Fragen zu Delphi Delphi #0 perfomanceschonend aus String entfernen
Thema durchsuchen
Ansicht
Themen-Optionen

#0 perfomanceschonend aus String entfernen

Ein Thema von Helmi · begonnen am 16. Feb 2010 · letzter Beitrag vom 17. Feb 2010
Antwort Antwort
Seite 2 von 2     12   
shmia

Registriert seit: 2. Mär 2004
5.508 Beiträge
 
Delphi 5 Professional
 
#11

Re: #0 perfomanceschonend aus String entfernen

  Alt 16. Feb 2010, 17:52
Zitat von p80286:
scheint mir "doppeltgemoppelt" und daher eigentlich ein Performance Killer.
Der Performance Killer ist die Indizierung durch den Array-Index.
Wenn da z.B. steht: s[i] , dann wird intern der Zeiger s genommen, dann wird i dazuaddiert, dies ergibt dann den Zeiger auf das zu lesende oder schreibende Zeichen.
Bei einem 4MB-String wären das 8 Millionen unnötige Additionen.

Hier die komplett getunte Funktion:
Delphi-Quellcode:
function StrReplaceChar(const S: Ansistring; const Source, Replace: AnsiChar): AnsiString;
var
  I: Integer;
  p : PAnsiChar;
begin
  Result := S;
  UniqueString(Result);
  p := PAnsiChar(Result);
  for I := Length(S)-1 downto 0 do
  begin
    if p^ = Source then
      p^ := Replace;
    Inc(p);
  end;
end;
Hier wird der Zeiger p einmal gesetzt und dann immer nur mit Inc() weiterbewegt.
Inc(p) wird direkt in einen einzigen (schnellen) X86-Befehl übersetzt.
Da die Schleifenvariable nicht mehr benützt wird, kann man die Schleife auch rückwärts laufen lassen.
Schleifen, die rückwärts runter auf 0 zählen sind besonders gut in Maschinencode zu übersetzen und daher sehr schnell.
Andreas
  Mit Zitat antworten Zitat
alzaimar
(Moderator)

Registriert seit: 6. Mai 2005
Ort: Berlin
4.956 Beiträge
 
Delphi 2007 Enterprise
 
#12

Re: #0 perfomanceschonend aus String entfernen

  Alt 16. Feb 2010, 18:39
[quote="shmia"]
Zitat von p80286:
Bei einem 4MB-String wären das 8 Millionen unnötige Additionen.
Ist das nicht eher indirekte Adressierung? Und was ist eigentlich das 'Inc(P)'? Ist das nicht auch eine Addition?

Meiner Erfahrung nach ist der Unterschied in diesem Fall marginal. Und wenn ich es ausprobiere, sehe ich auch keinen Unterschied. Ich würde dann die naive For-Schleife und einen stinknormalen String mit Index verwenden:
Delphi-Quellcode:
For i:=1 to Length(s) do
  if s[i]=ZuErsetzendesZeichen then
    s[i] := NeuesZeichen;
Zitat von shmia:
Hier die komplett getunte Funktion:...Schleifen, die rückwärts runter auf 0 zählen sind besonders gut in Maschinencode zu übersetzen und daher sehr schnell.
Hmm.. Zählt Dephi nicht automatisch rückwärts, wenn es keine Auswirkungen hat?
Hast Du wirklich verifiziert, das deine getunte Funktion schneller ist? Bei mir ist sie das nämlich nicht.

Ich stolpere immer wieder über diesen Vergleich zwischen Pointer und Indizierung. Bei solch naiven Schleifen sind beide gleich schnell, aber sobald man etwas mehr in der Schleife macht, ist die Pointer-Variante immer etwas schneller (20-30%, na ja, 'etwas'...)

Um es schneller zu bekommen, würde ich mir mal FastCode reinziehen, da gibt es eine 'CharPos' Funktion, die mit Sicherheit sehr viel schneller ist als die einfache Schleife. Sie verwendet Fluxkompensatoren, vierdimensionale Zeitfalten und *tunnelt* den Code, sodaß das das Programm fertig ist, bevor man überhaupt auf start gedrückt hat. Glaub ich jedenfalls.
"Wenn ist das Nunstruck git und Slotermeyer? Ja! Beiherhund das Oder die Flipperwaldt gersput!"
(Monty Python "Joke Warefare")
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.115 Beiträge
 
Delphi 12 Athens
 
#13

Re: #0 perfomanceschonend aus String entfernen

  Alt 16. Feb 2010, 19:34
Blos noch etwas Zusätzliches:

PChar(S) gibt nur einen Zeiger auf das erste String-Zeichen oder bei einem Leerstring auf einen "anderen" Bereich, welcher auf 0000 steht.

@S[1] ruft UniqueString auf und gibt einen Zeiger auf das 1. Zeichen oder nil zurück.

StringReplace und #0 im zu Suchstring, sowie im zu durchsuchendem String geht nicht, da CodEmba blöder Weise intern eine auf PChar-basierende Pos-Funktion nutzen, welche ja bekanntlich bei #0 stoppen.

PS: diese Move-Funktionen sind insoweit nicht gefährlich, wie man auf die Datengößen achtet und weiß was man tut.
Bei dem StringStream muß man in diesem Fall ab D2009 auch aufpassen, daß man nicht durch ein falsches/unpassendes Encoding die Daten zerschrottet.
PSS: Aus soeinem Grund hatte ich auch extra den AnsiString, statt String verwendet.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#14

Re: #0 perfomanceschonend aus String entfernen

  Alt 17. Feb 2010, 10:03
Hallo zusammen

ich hab mich dann mal aufgemacht und quickndirty versucht heraus zu bekommen was es in der Praxis bring:
Zitat:
---------------------
2063 1.lauf
---------------------
2000 2.lauf
Delphi-Quellcode:
function StrReplaceChar(const S: Ansistring; const Source, Replace: AnsiChar): AnsiString;
var
  I: Integer;
  p : PAnsiChar;
begin
  Result := S;
  UniqueString(Result);
  p := PAnsiChar(Result);
  for I := Length(S)-1 downto 0 do
  begin
    if p^ = Source then
      p^ := Replace;
    Inc(p);
  end;
end;

function StrReplaceChar_(const S: Ansistring; const Source, Replace: AnsiChar): AnsiString;
var
  I: Integer;
begin
  Result := S;
  UniqueString(Result);
  for I := Length(S)-1 downto 0 do
    if result[i] = Source then
      result[i] := Replace;
end;

procedure TForm1.Button1Click(Sender: TObject);
var
  i,j : integer;
  start1,
  start2,
  end1,
  end2 : integer;
  ts : string;
begin
  setlength(ts,4096*1024);

  fillchar(ts[1],length(ts),#32);
  for i:=1 to 4096 do
    if i mod 13 =0 then ts[i]:=#0;
  start1:=gettickcount;
  for j:=0 to 255 do
    StrReplaceChar(ts,#0,'A');
  end1:=gettickcount;
  {---------------------------------------------}
  fillchar(ts[1],length(ts),#32);
  for i:=1 to 4096 do
    if i mod 13 =0 then ts[i]:=#0;
  start2:=gettickcount;
  for j:=0 to 255 do
    StrReplaceChar_(ts,#0,'A');
  end2:=gettickcount;
  memo1.lines.add('---------------------');
  memo1.lines.add(inttostr(end1-start1)+' 1.lauf');
  memo1.lines.add('---------------------');
  memo1.lines.add(inttostr(end2-start2)+' 2.lauf');
end;
Ja ich weiß, Zeitmessung mit tickcount sind alles andere als genau, (ich hab die bessere Funktion nicht mehr gefunden) aber da der Fehler bei beiden Versionen auftritt ignorier ich ihn einfach.
Irgendwie drängt sich mir der Schluß auf, daß beide Varianten gleich schnell sind.

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.115 Beiträge
 
Delphi 12 Athens
 
#15

Re: #0 perfomanceschonend aus String entfernen

  Alt 17. Feb 2010, 10:15
Erstmal das:
sonst würde ja schon beim ersten Durchlauf alles erstetzt und die letzten 255 Mal passiert nicht mehr viel.


Und dann:
Tja, da siehst du mal, wie gut der Compiler optimiert.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#16

Re: #0 perfomanceschonend aus String entfernen

  Alt 17. Feb 2010, 11:24
Zitat von himitsu:
Erstmal das:
sonst würde ja schon beim ersten Durchlauf alles erstetzt und die letzten 255 Mal passiert nicht mehr viel.
Äh, willst Du mich auf den Arm nehmen? die Schleife über den String durchläuft er trotzdem, nur die eigentliche Ersetzen-Funktion fällt weg, und darum ging es Doch?

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Benutzerbild von himitsu
himitsu

Registriert seit: 11. Okt 2003
Ort: Elbflorenz
43.115 Beiträge
 
Delphi 12 Athens
 
#17

Re: #0 perfomanceschonend aus String entfernen

  Alt 17. Feb 2010, 11:32
Ups, ich glaub ich war vorhin so sehr in Klassenprozeduren vertieft, daß ich das Function glatt übersah.

Zitat von himitsu:
Tja, da siehst du mal, wie gut der Compiler optimiert.
Nja, dann bleibt immernoch das übrig.


Ach ja, das Andere wäre z.B. QueryPerformanceCounter gewesen,
aber auf die ~16 Millisekunden kommt es bei den "langen" Messzeiten wirklich nicht an.
Garbage Collector ... Delphianer erzeugen keinen Müll, also brauchen sie auch keinen Müllsucher.
my Delphi wish list : BugReports/FeatureRequests
  Mit Zitat antworten Zitat
Benutzerbild von p80286
p80286

Registriert seit: 28. Apr 2008
Ort: Stolberg (Rhl)
6.659 Beiträge
 
FreePascal / Lazarus
 
#18

Re: #0 perfomanceschonend aus String entfernen

  Alt 17. Feb 2010, 12:35
Mann könnte annehmen, daß heute Freitag ist.

???????????????????????????????????????????????

Gruß
K-H
Programme gehorchen nicht Deinen Absichten sondern Deinen Anweisungen
R.E.D retired error detector
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 23:31 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