![]() |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Liste der Anhänge anzeigen (Anzahl: 1)
Hallo,
coole Sache, dass ihr mit vielen Leuten das Projekt angegangen seid, ne Funktion zu optimieren. :dp: Ich wollte sie auch mal testen, um sie ggf. einzusetzen. Allerdings hab ich dabei (jedenfalls in meinem Fall) festgestellt, dass ich bereits ne schnellere Variante hatte (was mich angesichts eures Engagements bzgl. des Projekts etwas verwundert hatte). Aber ehe ich hier irgendwie falsch liege, möchte ich euch bitten, meine Variante doch auch mal zu testen (sie arbeitet allerdings auf array of string und nicht mit einer StringList). Je nach Ergebnis eurer Tests könnt ihr mich sehr gerne korrigieren oder eben meine Variante einbauen. Das soll jetzt nicht irgendwie eure Arbeit in Frage stellen, bitte nicht falsch verstehen. Ich wundere mich ja selbst über das Ergebnis meines Tests. :gruebel:
Delphi-Quellcode:
n ist das Pattern, s der große String.
function explode(const n,s : string) : TStringDynArray;
var temp : array of integer; Len : integer; x, count, laenge : integer; function follows(const s,n : string; pos1 : integer) : boolean; var x : integer; begin {if pos1 + length(n) > length(s)+1 then begin result := false; exit; end;} for x := 0 to length(n)-1 do if n[x+1] <> s[pos1 + x] then begin result := false; exit; end; result := true; end; begin x := 1; //SetLength(temp, 1); SetLength(temp, 20); count := 1; temp[0] := 1; laenge := Length(s) - Length(n) + 1; while x <= laenge do begin if follows(s,n,x) then begin inc(x, length(n)); //SetLength(temp, length(temp)+1); inc(count); if length(temp) < count then SetLength(temp, count + 20); //temp[high(temp)] := x; temp[count-1] := x; continue; end; inc(x); end; SetLength(temp, count); SetLength(result, length(temp)); for x := 0 to High(temp)-1 do begin Len := temp[x+1]-temp[x]-length(n); result[x] := copy(s, temp[x], Len); end; Len := length(s)-temp[high(temp)]+1; result[high(temp)] := copy(s, temp[high(temp)], Len); end; Ich hab das getestet mit folgender Datei im Anhang, hab sie 8x hintereinander in einen String reingetan (damit es auch wirklich viele Daten sind) und dann mit verschiedenen Patterns (#10, ' ', '0') getestet. Gruß Michael |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Super vielen Dank alzaimar!
Bin aber selbst nicht ganz durchgestiegen warum der Fehler überhaupt auftritt, wäre nett wenn mir das mal einer erklären könnte, weil eigentlich bin ich ja mit dem Index noch im Breich des Arrays :gruebel: |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
@MStoll:
In der Testumgebung aus dem 1.Post schneidet Deine Version zwischen 1.2 und 4x langsamer ab, als die vorgestellte Variante mit QuickSearch. Das ist aber auch nicht weiter verwunderlich. Der Quicksearch-Algorithmus spielt seine Stärken um so deutlicher aus, je länger der Suchtext und/oder Trenntext ist. Wenn der Trenntext aus genau einem Zeichen besteht, wird eine triviale Suche per Schleife aufgerufen. Du hast in deinen Tests ja nur nach diesem einen Zeichen gesucht und da wäre es denkbar, das Deine Variante aufgrund des geringeren Overheads besser abschneidet. In einem anderen ![]() @C.Schoch: Sei 'i' die aktuelle Position im Text T, p der zu suchende Text und Lp dessen Länge. Der Trick besteht darin, das Zeichen T[i+Lp] zu analysieren. Und dieser Wert T[i+Lp] kann eben leider auch Length(T)+1 sein. Das spielt unter C keine Rolle, denn dann ist T[i+Lp]=#0, aber bei Delphi ist das undefiniert, oder eben 'out of range'. Ich hatte immer den 'RangeCheck' ausgeschaltet, aber bei sehr großen Strings liegt dieser Wert dann trotzdem in der Pampa. Also muss man für den einen Fall (i=Length(T)-Lp+1) einen Sonderfall einbauen. Beispiel: Sei T='ABCDEFG', p= 'XYZ' und i=1. Da nun T[i+Lp]='D' nicht im Suchtext vorkommt, können wir gleich an die Stelle 5 springen und da unser Glück nochmal versuchen. Nun prüfen wir wieder das Zeichen T[i+Lp=5+3=8]. Hups, das gibts ja nicht, denn T ist ja nur 7 Zeichen lang=>Peng |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
@alzaimar:
Ok, das kann gut sein. :thumb: Hab es nicht mit mehr als einem Zeichen im Delimiter probiert. |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
30%- 75% Prozent Performancegewinn gewinnst Du bei einem Seperator der Länge 1, wenn Du die lokale Funktion in der Explode Procedure weglässt.
(ein Zeichen als Seperator braucht man ja häufig für CSV Files) Schon wenn die _AddString Procedure nur drin steht, und gar nicht aufgerufen wird, bricht die Performance durch den Aufruf-Stack massiv ein. TStrings ist auch ein sehr schwieriges Nadelöhr. Vielleicht besser doch ein Dynarray als Ergebnistyp verwenden, neuerdings kann man ja auch Records Definieren, die einen String beinhalten können, obwohl nicht als Shortstring deklariert. SetString könnte man noch durch die beste ASM Fastmove Funktion ersetzen. Dann wirds sogar noch schneller... Wenn man dann noch mit CSV Dateien arbeitet, und weiß, dass eine Spalte wahrscheinlich nie länger als 255 Zeichen wird, dann ist shortstring noch etwas schneller. Dann schafft man es auch, eine 100 MB CSV-Datei in 1,5 sec komplett zu durchforsten :-) die funktion muss also raus:
Delphi-Quellcode:
Procedure _AddString;
Var sTmp: String; Begin SetString(sTmp,ptrSubStr,Integer(ptrText) - Integer(ptrSubStr)); aItems.Add(sTmp) End; neue Variante:
Delphi-Quellcode:
Hier mal ein Performancevergleich:
Procedure TStringDivider.Explode(Const aText: String; aItems: TStrings);
Var ptrSubStr,ptrText,ptrTextEnd: PChar; sTmp: String; Begin If length(fPattern) > 1 Then QSExplode(aText,aItems) Else Begin aItems.clear; ptrText := PChar(@aText[1]); ptrSubStr := ptrText; ptrTextEnd := PChar(@aText[Length(aText)]); inc(ptrTextEnd); Repeat If ptrText^ = fPatternFirstChar Then Begin SetString(sTmp,ptrSubStr,Integer(ptrText) - Integer(ptrSubStr)); aItems.Add(sTmp); inc(ptrText); ptrSubStr := ptrText; End Else inc(ptrText); Until Integer(ptrText) = Integer(ptrTextEnd); SetString(sTmp,ptrSubStr,Integer(ptrText) - Integer(ptrSubStr)); aItems.Add(sTmp); End; End; Alte Variante: ------------------- Using TStringDivider in TStringList 100 chars per line: 1000000 lines in 2907 tics, 343997 lines per sec, 33,6 mb/s (del = ";") 100 chars per line: 1000000 lines in 1297 tics, 771010 lines per sec, 75,3 mb/s (del = "<Foobar>") 100 chars per line: 1000000 lines in 2187 tics, 457247 lines per sec, 44,7 mb/s (del = "ABCDE") 10000 chars per line: 50000 lines in 3781 tics, 13224 lines per sec, 129,1 mb/s (del = ";") 10000 chars per line: 50000 lines in 1422 tics, 35162 lines per sec, 343,4 mb/s (del = "<Foobar>") 10000 chars per line: 50000 lines in 2188 tics, 22852 lines per sec, 223,2 mb/s (del = "ABCDE") 1000000 chars per line: 500 lines in 3281 tics, 152 lines per sec, 148,8 mb/s (del = ";") 1000000 chars per line: 500 lines in 1047 tics, 478 lines per sec, 466,4 mb/s (del = "<Foobar>") 1000000 chars per line: 500 lines in 1718 tics, 291 lines per sec, 284,2 mb/s (del = "ABCDE") Neue Variante: ----------------- 100 chars per line: 1000000 lines in 2219 tics, 450653 lines per sec, 44,0 mb/s (del = ";") 100 chars per line: 1000000 lines in 1359 tics, 735835 lines per sec, 71,9 mb/s (del = "<Foobar>") 100 chars per line: 1000000 lines in 2172 tics, 460405 lines per sec, 45,0 mb/s (del = "ABCDE") 10000 chars per line: 50000 lines in 2234 tics, 22381 lines per sec, 218,6 mb/s (del = ";") 10000 chars per line: 50000 lines in 1438 tics, 34771 lines per sec, 339,6 mb/s (del = "<Foobar>") 10000 chars per line: 50000 lines in 2219 tics, 22533 lines per sec, 220,0 mb/s (del = "ABCDE") 1000000 chars per line: 500 lines in 1875 tics, 267 lines per sec, 260,4 mb/s (del = ";") 1000000 chars per line: 500 lines in 984 tics, 508 lines per sec, 496,2 mb/s (del = "<Foobar>") 1000000 chars per line: 500 lines in 1735 tics, 288 lines per sec, 281,4 mb/s (del = "ABCDE") 30% Performancezuwachs (del = ";") - 100 chars per line: 1000000 lines 70% Performancezuwachs (del = ";") - 10000 chars per line: 50000 lines 75% Performancezuwachs (del = ";") - 1000000 chars per line: 500 lines |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Liste der Anhänge anzeigen (Anzahl: 1)
Hi Stoxx,
Danke für die Tipps. Ich habe mittlerweile eine Version, die die FastCode-Gewinner mit einbezieht. Bei Trennern der Länge 1 ist die neue Version um ein vielfaches schneller. ![]() Meine Pos-Version ist im Anhang, wenn Du magst, kannst Du das ja in die Explode-Routine einbauen. Ganz speziell das sehr schnelle 'CharPos' dürfte interessant sein. In einer QSearch-Version war der Fehlerteufel drin. Ich hoffe, das das bei der hier nicht der Fall ist. Wenn der Trenner ganz am Ende steht, hat die ursprüngliche QSearch-Variante versagt. Die Version im Anhang arbeitet korrekt. [edit] Was hab ich bloß für ungetesteten Müll auf meinem Laptop? Da war doch glatt ein Fehler drin [/edit] Kurz getestet (CharPos und FastMove): Geschwindigkeitszuwachs 7-50% |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Zitat:
Zitat:
aber dafür ist ja explode nicht gedacht, oder doch? einen schönen guten morgen GG |
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Nein.
|
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Zitat:
|
Re: [Optimiert] Explode Prozedur - Reloaded (Ersatz für Code
Zitat:
Das wäre ganz nett von Dir!! Zitat:
Vielleicht magst die ja noch in den ersten Post dranhängen? ... nicht ersetzen, das wäre nicht gar so schön ... Die kritischste Zeit in Deiner Implementierung ist eigentlich das zweimal "harte" kopierens des Strings einmal in einem Tempstring und dann nochmal in eine Tstringlist (TStrings) .. Und zusätzlich glaube ich nicht, dass man die Dividerklasse so verwenden möchte, dass als Endprodukt eine Tstringliste der getrennten Strings haben möchte, sondern man möchte ja eher per Index auf die einzelnen Elemente zugreifen können. Man würde also Deine Rückgabe TStrings nochmal durchlaufen, und erst dann verarbeiten. Besser ist es also wenn man die reine Explodefunktion ohne Kapslung intelligent in seine eigene Klasse einbaut, die dann noch einen Indexzugriff hat, auf die einzelnen elemente per property hat, wo eine Stringkopie erst im allerletzten Moment zum beispiel an eine StrToFloatDef() Funktion geleitet wird... |
Alle Zeitangaben in WEZ +1. Es ist jetzt 07:05 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