Delphi-PRAXiS
Seite 2 von 3     12 3      

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Sonstige Fragen zu Delphi (https://www.delphipraxis.net/19-sonstige-fragen-zu-delphi/)
-   -   Delphi Diese funktion schneller machen? (https://www.delphipraxis.net/32897-diese-funktion-schneller-machen.html)

Nothine 30. Okt 2004 10:11

Re: Diese funktion schneller machen?
 
weil S := PChar(Text) intern LStrToPChar aufruft, S := Pointer(Text) dagegen übergibt wirklich nur die adresse von @Text[1] an S

GaP 30. Okt 2004 10:25

Re: Diese funktion schneller machen?
 
Hi,

ich stell einfach mal die Funktion mit der ich solche Aufgaben erledige in den Raum, ob sie schneller ist oder nicht kann ich nicht sagen, vllt. kann ja noch jemand Tipps geben... :)

Delphi-Quellcode:
function W(Wort: Integer; Text, Zeichen: String): String;
var Anfang, Ende, i: Integer;
begin
  Anfang := 0;
  Ende := 0;
  if Pos(Zeichen, Text) = 0 then Result := '' else begin
    if Wort = 1 then begin
      Anfang := Pos(Zeichen, Text);
      Result := MidStr(Text, 1, Anfang-1);
    end
    else begin
      for i:=1 to Wort-1 do Anfang := PosEx(Zeichen, Text, Anfang+1);
      if PosEx(Zeichen, Text, Anfang+1) = 0 then Ende := Length(Text)
      else Ende := PosEx(Zeichen, Text, Anfang+1)-Anfang-1;
      Result := MidStr(Text, Anfang+1, Ende);
    end;
  end;
end;

negaH 30. Okt 2004 10:54

Re: Diese funktion schneller machen?
 
@Nothine: tja, das sind solche internen Änderungen zwischen den einzelnen Delphi Versionen. Bis Delphi 5 bin ich mir sicher das intern PChar(String) identisch zu Pointer(String) ist. Wenn aber in Delphi 7 intern LStrToPChar() aufgerufen wird dann muß das seine Gründe haben. Da wir unbedingt einen 0-terminierten PChar benötigen würde ich es so lassen wie es ist. Einfach der Kompatibilität halber.

Grundsätzlich dürfte damit meine Funktion nicht wesentlich langsammer werden, und davon mal abgesehen ist sie um vielfaches schneller als alle Varianten die mit Pos(), PosEx(), MidStr(), Delete() usw. arbeiten. Und meiner Meinung nach sogar viel einfacher zu verstehen ;)

Gruß Hagen

DeerHunter 30. Okt 2004 11:05

Re: Diese funktion schneller machen?
 
mal eine Frage am Rande: wo ist der unterschied zwischen Pos und PosEx? letzteres scheint es wohl erst ab Delphi 7 zu geben, oder?

Nothine 30. Okt 2004 11:12

Re: Diese funktion schneller machen?
 
@Hagen: klar, ich sag ja auch gar nichts gegen deine funktionen, du bist der profi hier, nich ich :mrgreen: und es ging ja auch nur darum wie man es schneller macht, und eine einfache pointerzuweisung is nu ma schneller :roll: und ich glaube ich muss dich enttäuschen, aber die information das intern LStrToPChar aufgerufen wird habe ich gerade eben meinem delphi 5(!) entnommen :wink:

@DeerHunter: jap, PosEx is erst später hinzugekommen und definiert zusätzlich einen start-offset, bei dem die suche beginnt

negaH 30. Okt 2004 11:33

Re: Diese funktion schneller machen?
 
Stimmt, habe gerade nochmal in die RTL reingeschaut ;)

Allerdings muss PChar(String) dann benutzt werden, denn wenn Pointer(String) == NIL ist, wandelt _LStrToPChar() -> PChar(String) diesen NIL Zeiger in einen Zeiger auf einen PChar mit Null-Terminator um.
Wenn man also Pointer(String) benutzen will so muß man danach zusätzlich abfragen ob dieser Zeiger NIL ist. Dies wird dann aber wirklich nur 4-8 CPU Takte schneller sein als ein PChar(String).

Es lohnt also nicht sich vom "Standardkonformen" Weg zu entfernen und Pointer(String) statt PChar(String) zu benutzen.

Gruß Hagen

Nothine 30. Okt 2004 11:40

Re: Diese funktion schneller machen?
 
okok, weniger tippen müsste man natürlich bei S := PChar(Text), andererseits stellt sich die frage ob man nicht eh am anfang der routine prüft ob Text = '', weil was will man aus einem leeren string schon an tokens oder indizes auslesen? :roll:

negaH 30. Okt 2004 12:36

Re: Diese funktion schneller machen?
 
Ja, man könnte jeden Spezialfall mit einer eigenen Abfrage programmieren. Ich persönlich hasse das aber. Lieber die Funktionen so allgemein, kurz und schnell wie möglich halten.
Zb. in meinem obigem Vorschlag würde bei Text = '';

Delphi-Quellcode:
while (S^ <> #0) ... do;
schon zuschlagen. D.h. eine einzigste Abfrage. Dann weiter:

Delphi-Quellcode:
D := S;
while (D^ <> #0) do ;
eine Zuweisung -> "MOV Reg1, reg2" und eine Abfrage wiederum.
Und am Schluß

Delphi-Quellcode:
  SetString(Result, S,D - S);
eine Subtraktion "SUB ECX,EDX"und ein CALL _SetLength(EAX, EDX, ECX);

Damit ist der UNWAHRSCHEINLICHSTE Fall, das Text == '' ist, genügend abgedeckt. Viel wahrscheinlicher sind aber Strings <> '', und somit würde eine ständige vorherige und spezielle Abfrage auf Text = '' eher bremsen als sinnvoll sein.

Programmiere immer nur soviel wie absolut nötig ist, verkompliziere nicht die Logik mit Abfragen die vom Programmfluß eher am unwahrscheinlichsten sind. Als Resulat kommt eine Lösung heraus die man leicht versteht und gut optimiert und denoch kurz und bündig ist.

Momentan sehe ich echt keinen Grund bzw. weitere Möglichkeit meine Funktion weiter zu verbessern.

Gruß Hagen

Nothine 30. Okt 2004 13:21

Re: Diese funktion schneller machen?
 
obwohl sie gegen ende umständlicher aussieht, ist diese
Delphi-Quellcode:
function ExtractToken(const Text: string; Index: Integer; const Separator: Char = ' '): string;
var S,D: PChar;
begin
  S := PChar(Text);
  while (S^ <> #0) and (Index > 0) do begin
    if S^ = Separator then Dec(Index);
    Inc(S);
  end;
  D := S;
  while (D^ <> #0) and (D^ <> Separator) do Inc(D);
  SetLength(Result,D-S);
  D := Pointer(Result);
  while (S^ <> Separator) and (S^ <> #0) do begin
    D^ := S^;
    Inc(S);
    Inc(D);
  end;
end;
funktion auf meinem system bei 10000000 wiederholungen ca. 600 millisekunden schneller, bitte um test deinerseits

edit: nur noch zur info, zeitversuch nach dem GetTickCount-prinzip

negaH 30. Okt 2004 14:31

Re: Diese funktion schneller machen?
 
probier mal

Delphi-Quellcode:
  R := Pointer(Result);
  while S < D do
  begin
    R^ := S^;
    Inc(S);
    Inc(R);
  end;

// oder
 
  R := Pointer(Result);
  for I := 0 to D - S -1 do
    R[I] := S[I];
Das SetString() langsammer sein kann auf modernen CPU's im Gegensatz zu einer eigenen Loop kann durchaus so sein. Allerdings beachte das du mit dynamisch allozierten Strings arbeitest, und dein Test eventuell immer wieder die gleichen Speicherbereiche benutzt da der Speicher Manager so arbeitet. In einem solchen Falle, und nur in einem solchen Fall, kann eine einfache Loop schneller sein als das REP MOVSW in Copy()->SetString().
Du solltest also deine Tests so aufbauen das nacheinander, sozusagen verschachtelt immer wieder neue Speicherbereiche alloziert werden. Zudem solltest du die Funktion INNERHALB von vielen anderen Funktionen testen. Also simulierst du die wahrscheinlichst realen Bedingungen der Anwendung der Funktion innerhalb eines Programmes. Ich vermute das du einfach in deinen Tests in einer Schleife die Funktion mit den gleichen Daten aufgerufen hast. Solche Test sagen fast garnichts über die realen Verhältnisse der Funktion in realen Programmen aus.

Gruß Hagen


Alle Zeitangaben in WEZ +1. Es ist jetzt 15:13 Uhr.
Seite 2 von 3     12 3      

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