Zeilenweise Ausgabe optimieren...
Zeilenweise Ausgabe optimieren...
Also das Thema ist bei mir dauernd interessant u.a in einem größeren Sortierfall, wenn Zwischendateien gebildet, sortiert und wieder eingemischt werden müssen und dann tatsächlich das Mischen/Kopieren der Flaschenhals ist und 2/3 der Zeit benötigt. An einer Beschleunigung der einfachen Readln/Writeln war ich schon zig Jahre interessiert und habe scheinbar nie etwas gefunden. Nun schon (siehe meine Anlage).
Was mir (negativ) auffiel, das Stringlist.LoadFromFile ist sehr fix, das StringlistSaveToFile dagegen eine mehr als lahme Ente. So lahm, daß ich beim Sortieren von der Stringlist Abstand genommen und eine eigene Liste implementiert hatte. Die Sortieralgorithmen halten sich wohl die Waage, nur daß die Stringliste bei Millionen Zeilen abkackt und meins nicht, egal Zwischendateien brauchte ich trotzdem.
Nun habe ich mit dem SaveLineBuffered (Unit OptIO) anscheinend etwas Brauchbares gefunden, was das einfache Writeln doch topt bzw ja dropt und das ReadLineBuffered nach längeren Irren und Wirren auch. Habe bei meinen Zieldatenstrukturen (Array fest bzw dynamisch, einfach bzw doppelt verkettete Listen, Stacks usw) keine Fehler mehr gefunden.
Dann wollte ich mich wagen an das StringList.SaveToFileFast und es scheint mir auch gelungen. Jedenfalls finde ich in den Ausgaben keine offensichtlichen Fehler mehr und die Laufzeit ist akzeptabel (mehr als 10x schneller als SaveToFile und auch noch bedeutend schneller als das einfache Writeln). Könnte da bitte mal jemand drüberschauen? Habe ich etwas übersehen oder gibt es noch schnellere Kandidaten? Den Stringbuilder hatte ich auch am Wickel aber ich fand das Blockwrite für mich logischer.
Was mir (negativ) auffiel, das Stringlist.LoadFromFile ist sehr fix, das StringlistSaveToFile dagegen eine mehr als lahme Ente. So lahm, daß ich beim Sortieren von der Stringlist Abstand genommen und eine eigene Liste implementiert hatte. Die Sortieralgorithmen halten sich wohl die Waage, nur daß die Stringliste bei Millionen Zeilen abkackt und meins nicht, egal Zwischendateien brauchte ich trotzdem.
Nun habe ich mit dem SaveLineBuffered (Unit OptIO) anscheinend etwas Brauchbares gefunden, was das einfache Writeln doch topt bzw ja dropt und das ReadLineBuffered nach längeren Irren und Wirren auch. Habe bei meinen Zieldatenstrukturen (Array fest bzw dynamisch, einfach bzw doppelt verkettete Listen, Stacks usw) keine Fehler mehr gefunden.
Dann wollte ich mich wagen an das StringList.SaveToFileFast und es scheint mir auch gelungen. Jedenfalls finde ich in den Ausgaben keine offensichtlichen Fehler mehr und die Laufzeit ist akzeptabel (mehr als 10x schneller als SaveToFile und auch noch bedeutend schneller als das einfache Writeln). Könnte da bitte mal jemand drüberschauen? Habe ich etwas übersehen oder gibt es noch schnellere Kandidaten? Den Stringbuilder hatte ich auch am Wickel aber ich fand das Blockwrite für mich logischer.
- Dateianhänge
-
saveopt.zip
- (289.57 KiB) 109-mal heruntergeladen
-
- Beiträge: 7007
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Zeilenweise Ausgabe optimieren...
Evtl ist FileStream oder MemoryStream eine Alternative. Read und Write sind nicht unbedingt Raketen, vor allem wen man Byteweise einliest.An einer Beschleunigung der einfachen Readln/Writeln war ich schon zig Jahre interessiert und habe scheinbar nie etwas gefunden.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
Re: Zeilenweise Ausgabe optimieren...
Ich möchte eigentlich schon zeilenweise nicht byteweise lesen.
Was machen die beiden von dir genannten Klassen(?) anders als das Blockwrite oder Stringbuilder?
Was machen die beiden von dir genannten Klassen(?) anders als das Blockwrite oder Stringbuilder?
Re: Zeilenweise Ausgabe optimieren...
Ich habe mich nun für TStringArray und entweder
- eine Kombination aus normalen Readln und gepufferten Blockwrite entschieden
- eventuell auch ein neues, auf TStream basierendes ReadAllLines und WriteAllLines, welches noch ca 10% schneller wäre, aber bei 32bit zu früh an Speichergrenzen gerät (vielleicht kombiniere ich das auch).
Den notwendigen Array Sort habe ich gefunden, er ist sogar schneller als mein bisheriger Listen/Pointer-basierter.
Aber beim Testen ist mir nun eine Sache aufgefallen, die mir bisher nicht so bewußt war: Der Standard SL.Sort ist sooooo langsam? Bis zu 10x langsamer?
25s bei 2 Mio Zeilen zufälligen Inhaltes gegenüber max 2s beim Array-Sort. Mein altes Projekt ist da bei 4s allerdings schon mit Teilen und Merge (standardmäßig bei 1 Mio).
Ich kann das bei einer Standard-Methode einfach nicht glauben, was mache ich falsch. Ich dachte bisher immer es liegt am SL.SaveToFile (und habe den optimiert). Aber der Sort selber als Bremse?
- eine Kombination aus normalen Readln und gepufferten Blockwrite entschieden
- eventuell auch ein neues, auf TStream basierendes ReadAllLines und WriteAllLines, welches noch ca 10% schneller wäre, aber bei 32bit zu früh an Speichergrenzen gerät (vielleicht kombiniere ich das auch).
Den notwendigen Array Sort habe ich gefunden, er ist sogar schneller als mein bisheriger Listen/Pointer-basierter.
Aber beim Testen ist mir nun eine Sache aufgefallen, die mir bisher nicht so bewußt war: Der Standard SL.Sort ist sooooo langsam? Bis zu 10x langsamer?
25s bei 2 Mio Zeilen zufälligen Inhaltes gegenüber max 2s beim Array-Sort. Mein altes Projekt ist da bei 4s allerdings schon mit Teilen und Merge (standardmäßig bei 1 Mio).
Ich kann das bei einer Standard-Methode einfach nicht glauben, was mache ich falsch. Ich dachte bisher immer es liegt am SL.SaveToFile (und habe den optimiert). Aber der Sort selber als Bremse?
Code: Alles auswählen
PROGRAM XCopy7; (* StringList(SL), SL.LoadFromFile, SL.SaveToFileFast SL.Sort *)
{$mode objfpc}
USES
Stdio, Zeit, WaitKey, Classes, SLOpt;
VAR
EinName, AusName: STRING;
EinZahl, AusZahl: CARD;
Sortieren : BOOLEAN;
SL: TStringList;
BEGIN
Intervall_Start(10);
Sortieren := FALSE;
IF PARAMSTR(1) <> '' THEN EinName := PARAMSTR(1)
ELSE EinName := 'input' + {$IFNDEF DOS} '12' {$ELSE} '03' {$ENDIF} + '.txt';
IF PARAMSTR(2) <> '' THEN AusName := PARAMSTR(2)
ELSE AusName := 'output' + {$IFNDEF DOS} '12' {$ELSE} '03' {$ENDIF} + '.txt';
IF (PARAMSTR(3) <> '') OR ((PARAMSTR(1) = '') AND (PARAMSTR(2) = '')) THEN Sortieren := TRUE;
Writeln('Kopiere ('+_ue+'ber SL) ', EinName, ' nach ', AusName);
Writeln('SL LoadFromFile ', Intervall_Start(1));
SL := TSTringList.Create;
SL.LoadFromFile(EinName);
EinZahl := SL.Count;
Writeln(Intervall_Stop(1) + ' ' + Intervall_Dauer(1));
Writeln('Anzahl Eingabe: ', StrCard(EinZahl));
IF Sortieren THEN BEGIN
Writeln('Sortieren SL ', Intervall_Start(2));
SL.Sort;
Writeln(Intervall_Stop(2) + ' ' + Intervall_Dauer(2));
Writeln('Zeilen SL/Sortiert: ', StrCard(SL.Count));
END;
Writeln('SL SaveToFileFast ', Intervall_Start(3));
//SL.SaveToFile(AusName);
SL.SaveToFileFast(AusName);
AusZahl := SL.Count;
Writeln(Intervall_Stop(3) + ' ' + Intervall_Dauer(3));
Writeln('Anzahl Ausgabe: ', StrCard(AusZahl));
Intervall_Stop(10);
Writeln('Gesamt: ', Intervall_Dauer(10));
Wait;
END.
-
- Beiträge: 7007
- Registriert: Do 2. Jan 2014, 17:21
- OS, Lazarus, FPC: Linux (die neusten Trunk)
- CPU-Target: 64Bit
- Wohnort: Schweiz
Re: Zeilenweise Ausgabe optimieren...
Da wäre recht spannend, was die STringList für eine Sortierroutine verwendet. Ob da was anderes als QSort verwendet wird ?Aber beim Testen ist mir nun eine Sache aufgefallen, die mir bisher nicht so bewußt war: Der Standard SL.Sort ist sooooo langsam? Bis zu 10x langsamer?
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot
Mit Java und C/C++ sehe ich rot
Re: Zeilenweise Ausgabe optimieren...
Zu dumm, dass wir keinen Quelltext haben...Mathias hat geschrieben: Do 7. Aug 2025, 14:14 Da wäre recht spannend, was die STringList für eine Sortierroutine verwendet. Ob da was anderes als QSort verwendet wird ?

procedure TStringList.QuickSort(L, R: Integer; CompareFn: TStringListSortCompare );
Re: Zeilenweise Ausgabe optimieren...
ich habe mittlerweile mit ChatGPT herausgefunden, daß da wohl eine alte Delphi-Routine sortiert, die nie rausgenommen wurde, weil anscheinend kein Bedarf an Sortieren bei so großen Stringlists und weil wohl Rücksicht auf andere Methoden genommen wird, die TStringList hat (sorry falls ich das falsch wiedergebe).Mathias hat geschrieben: Do 7. Aug 2025, 14:14Da wäre recht spannend, was die STringList für eine Sortierroutine verwendet. Ob da was anderes als QSort verwendet wird ?Aber beim Testen ist mir nun eine Sache aufgefallen, die mir bisher nicht so bewußt war: Der Standard SL.Sort ist sooooo langsam? Bis zu 10x langsamer?
Aber!! Und dann kam die große Entdeckung des Tages für mich - und wieder sorry falls Euch allen das so klar ist, ich bin in Bezug auf die Lazarus-Objekte noch immer Anfänger und ich war erstaunt und leicht euphorisiert, als ich las, die einzelnen Strings der TStringList lassen sich über einen Index ansprechen. Also A[0] bis A[len-1],
Darauf hin habe ich glatt meinen TStringArray Quicksort 1:1 darauf angesetzt und voíla nur 5-10% langsamer als beim TStringArray. Aber schon mal nicht mehr 10 MAL langsamer.
Dann habe ich noch die Compare-Funktion entschlackt und nun sind die beiden Quicksorts vergleichbar. Rätsel gelöst und ich stehe vor der Qual der Wahl, welches ich in meinem Anwendungsprogramm nehmen soll. TStringList lädt und sichert doch noch einen Tick schneller, dafür ist bei TStringArray der Sort etwas fixer. Mal sehen. Meinen aktualisierten Benchmark werde ich noch nachreichen, dazu fehlt mir aber noch ein Puzzleteil und das ist in den Tiefen meines Stacks äh Kellers gut versteckt.
Code: Alles auswählen
UNIT SLOpt;
{$mode objfpc}{$H+}
INTERFACE
USES
Classes, SysUtils;
TYPE
TStringCompareFunc = FUNCTION(CONST A, B: STRING): INTEGER;
TStringListHelper = CLASS HELPER FOR TStringList
PROCEDURE SaveToFileFast(CONST FileName: STRING);
PROCEDURE QuickSortFast;
END;
IMPLEMENTATION
FUNCTION CompareStringsFast(CONST TextA, TextB: STRING): INTEGER;
BEGIN
// Schneller, bin_aerer Vergleich (ohne Gro_sz-/Kleinschreibung zu ignorieren)
CompareStringsFast := CompareStr(TextA, TextB);
END;
PROCEDURE QuickSortSL(Strings: TStringList; LeftIndex, RightIndex: INTEGER; CompareFunc: TStringCompareFunc);
VAR
IndexLeft, IndexRight: INTEGER;
Pivot, Temp: STRING;
BEGIN
IndexLeft := LeftIndex;
IndexRight := RightIndex;
Pivot := Strings[(LeftIndex + RightIndex) DIV 2];
REPEAT
WHILE CompareFunc(Strings[IndexLeft], Pivot) < 0 DO INC(IndexLeft);
WHILE CompareFunc(Strings[IndexRight], Pivot) > 0 DO DEC(IndexRight);
IF IndexLeft <= IndexRight THEN BEGIN
Temp := Strings[IndexLeft];
Strings[IndexLeft] := Strings[IndexRight];
Strings[IndexRight] := Temp;
INC(IndexLeft);
DEC(IndexRight);
END;
UNTIL IndexLeft > IndexRight;
IF LeftIndex < IndexRight
THEN QuickSortSL(Strings, LeftIndex, IndexRight, CompareFunc);
IF IndexLeft < RightIndex
THEN QuickSortSL(Strings, IndexLeft, RightIndex, CompareFunc);
END;
PROCEDURE TStringListHelper.QuickSortFast;
BEGIN
IF Self.Count > 1
THEN QuickSortSL(Self, 0, Self.Count - 1, @CompareStringsFast);
END;
PROCEDURE TStringListHelper.SaveToFileFast(CONST FileName: STRING);
CONST
BufferSize = 65536;
VAR
OutputFile: FILE;
OutputBuffer: ARRAY[0..BufferSize - 1] OF BYTE;
BufferPtr: PByte;
BufferFill, LineLength, LineIndex: INTEGER;
LineData: STRING;
BEGIN
AssignFile(OutputFile, FileName);
System.Rewrite(OutputFile, 1);
BufferPtr := @OutputBuffer[0];
BufferFill := 0;
FOR LineIndex := 0 TO Self.Count - 1 DO BEGIN
LineData := Self[LineIndex] + LineEnding;
LineLength := Length(LineData);
IF BufferFill + LineLength > BufferSize THEN BEGIN
BlockWrite(OutputFile, OutputBuffer, BufferFill);
BufferFill := 0;
BufferPtr := @OutputBuffer[0];
END;
System.Move(LineData[1], BufferPtr^, LineLength);
INC(BufferPtr, LineLength);
INC(BufferFill, LineLength);
END;
IF BufferFill > 0
THEN BlockWrite(OutputFile, OutputBuffer, BufferFill);
CloseFile(OutputFile);
END;
BEGIN
END.
Re: Zeilenweise Ausgabe optimieren...
Leider weiß man bei KI nie, ob eine Aussage die Wahrheit oder Einbildung ist...alfware17 hat geschrieben: Do 7. Aug 2025, 15:02 ich habe mittlerweile mit ChatGPT herausgefunden, daß da wohl eine alte Delphi-Routine sortiert, die nie rausgenommen wurde, weil anscheinend kein Bedarf an Sortieren bei so großen Stringlists und weil wohl Rücksicht auf andere Methoden genommen wird, die TStringList hat (sorry falls ich das falsch wiedergebe).
Den Quicksort musst du in TStringList nicht selbst implementieren, der ist (als private Methode "QuickSort") schon eingebaut, wird aber nur aktiviert, wenn die Eigenschaft Sorted=true ist (und damit wird auch gleich sortiert).
Re: Zeilenweise Ausgabe optimieren...
Wird dann beim Load gleich sortiert? Oder erst wenn ich das Sorted (mit meine.Sorted:=true nehme ich an?) setze. Sag jetzt nicht, ich kann es doch ausprobieren...wp_xyz hat geschrieben: Do 7. Aug 2025, 15:13Leider weiß man bei KI nie, ob eine Aussage die Wahrheit oder Einbildung ist...alfware17 hat geschrieben: Do 7. Aug 2025, 15:02 ich habe mittlerweile mit ChatGPT herausgefunden, daß da wohl eine alte Delphi-Routine sortiert, die nie rausgenommen wurde, weil anscheinend kein Bedarf an Sortieren bei so großen Stringlists und weil wohl Rücksicht auf andere Methoden genommen wird, die TStringList hat (sorry falls ich das falsch wiedergebe).
Den Quicksort musst du in TStringList nicht selbst implementieren, der ist (als private Methode "QuickSort") schon eingebaut, wird aber nur aktiviert, wenn die Eigenschaft Sorted=true ist (und damit wird auch gleich sortiert).
Mache ich sowieso, aber erstmal war ich so stolz daß ich das mit dem Zugriff über die Indexe herausgefunden habe.
Ich nahm an der private Quicksort sieht dann genau so aus, wie der den ich in den Helper gebaut habe, aber das was ich im Github sah, sieht irgendwie ähnlich aber doch anders aus. Und meine Frage bleibt, warum ist der 10x langsamer?
Die Quicksort Routine im Github löst den zweiten rekursiven Aufruf irgendwie in einem Repeat drum herum auf. Und es wird AnsiCompare benutzt. Aber ob das so ein Zehnfaches ausmacht? Ich habe schon gesucht, ob ich das falsch aufrufe, aber anscheinend ist der Unterschied in der Performance da
Code: Alles auswählen
procedure TStringList.QuickSort(L, R: Integer; SCompare: TStringListSortCompare);
var I, J, P, Tmp: Integer;
begin
repeat
I := L;
J := R;
P := (L+R) shr 1;
repeat
while SCompare(Self,I,P)<0 do Inc(I);
while SCompare(Self,J,P)>0 do Dec(J);
if I <= J then begin
Tmp := integer(fListObj[I]);
fListObj[I] := fListObj[J];
fListObj[J] := pointer(Tmp);
Tmp := integer(FListStr[I]);
integer(FListStr[I]) := integer(FListStr[J]);
integer(FListStr[J]) := Tmp;
if P=I then
P := J else
if P=J then
P := I;
Inc(I);
Dec(J);
end;
until I>J;
if L<J then QuickSort(L,J,SCompare);
L := I;
until I>=R;
end;
procedure TStringList.SetSorted(Value: Boolean);
begin
if FSorted <> Value then begin
if Value then
Sort;
FSorted := Value;
end;
end;
function StringListCompareStrings(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := List.CompareStrings(List.fListStr[Index1],List.fListStr[Index2]);
end;
procedure TStringList.Sort;
begin
CustomSort(StringListCompareStrings);
end;
procedure TStringList.CustomSort(Compare: TStringListSortCompare);
begin
if (self=nil) or (FCount<=1) then
exit;
QuickSort(0,FCount-1,Compare);
end;
function TStringList.CompareStrings(const S1, S2: string): Integer;
begin
if CaseSensitive then
Result := AnsiCompareStr(S1, S2) else
Result := AnsiCompareText(S1, S2);
end;
Re: Zeilenweise Ausgabe optimieren...
Hier ein Speed-Test für verschiedene Sortier-Optionen. Es werden zunächst 200.000 zufällige Strings in einer Stringlist gespeichert. In den folgenden Tests werden diese Strings immer wieder in eine "frische" Stringlist eingefügt und unter verschiedenen Bedingungen sortiert. Bedingungen sind: wann erfolgt die Sortierung, welche String-Vergleichs-Funktion wird verwendet (case-sensitive, use locale), wird die Stringlist zu Beginn schon auf die Endzahl der Einträge dimensioniert (Capacity = N), oder wird die Listengröße beim Überschreiten der bisherigen Größe verdoppelt (Capacity = 0)?
- 1. Test: Zu Beginn gleich Sorted := true setzen. Damit wird jeder String beim Einfügen gleich richtig einsortiert.
- 2. Test: Die Strings werden (mit Sorted = false) in die Zielliste eingefügt, und am Ende wird Sorted auf true gesetzt
- 3. Test: genauso, nur wird statt Sorted = true manuell die Sort-Methode aufgerufen
- 4. Test: genauso, nur wird statt Sort die CustomSort-Methode aufgerufen, einmal mit CompareStr und einmal mit AnsiCompareStr
- 5. Test: genauso, nur wird statt CustomSort deine StringHelper-Sortierung aufgerufen.
Ergebnisse:
Am schnellsten sind Sorted=true und Sort nach dem Einfügen, wenn die Strings "pur" verglichen werden (keine Groß/Kleinschreibung, keine Berücksichtigung von Ländereigenheiten), gefolgt von deinem StringList-Helper. Abgeschlagen die Idee, die Strings schon beim Einlesen zu sortieren.
Die Vordimensionierung der Listengröße hat überraschenderweise keinen messbaren Effekt.
- 1. Test: Zu Beginn gleich Sorted := true setzen. Damit wird jeder String beim Einfügen gleich richtig einsortiert.
- 2. Test: Die Strings werden (mit Sorted = false) in die Zielliste eingefügt, und am Ende wird Sorted auf true gesetzt
- 3. Test: genauso, nur wird statt Sorted = true manuell die Sort-Methode aufgerufen
- 4. Test: genauso, nur wird statt Sort die CustomSort-Methode aufgerufen, einmal mit CompareStr und einmal mit AnsiCompareStr
- 5. Test: genauso, nur wird statt CustomSort deine StringHelper-Sortierung aufgerufen.
Ergebnisse:
Code: Alles auswählen
Creating 200.000 test strings --> 0.036 secs
Capacity = 0
Insert sorted (case-sensitive: yes, use locale: yes) --> 6.499 secs
Insert sorted (case-sensitive: no, use locale: yes) --> 6.536 secs
Insert sorted (case-sensitive: no, use locale: no ) --> 6.133 secs
Insert unsorted, set Sorted to true at end (case-sensitive: yes, use locale: yes) --> 0.820 secs
Insert unsorted, set Sorted to true at end (case-sensitive: no, use locale: yes) --> 0.793 secs
Insert unsorted, set Sorted to true at end (case-sensitive: no, use locale: no ) --> 0.080 secs
Insert unsorted, call Sort() at end (case-sensitive: yes, use locale: yes) --> 0.768 secs
Insert unsorted, call Sort() at end (case-sensitive: no, use locale: yes) --> 0.767 secs
Insert unsorted, call Sort() at end (case-sensitive: no, use locale: no ) --> 0.079 secs
Insert unsorted, call CustomSort(@CompareStr) at end --> 0.176 secs
Insert unsorted, call CustomSort(@AnsiCompareStr) at end --> 0.885 secs
Insert unsorted, call helper for sorting at end --> 0.129 secs
Press ENTER to close...
Die Vordimensionierung der Listengröße hat überraschenderweise keinen messbaren Effekt.
Code: Alles auswählen
program StringList_Speed;
uses
SysUtils, Classes;
type
TStringCompareFunc = function(const A, B: String): Integer;
TStringListHelper = class helper for TStringList
procedure QuickSortFast;
end;
function CompareStringsFast(const TextA, TextB: String): Integer;
begin
// Schneller, bin_aerer Vergleich (ohne Gro_sz-/Kleinschreibung zu ignorieren)
Result := CompareStr(TextA, TextB);
end;
procedure QuickSortSL(Strings: TStringList; LeftIndex, RightIndex: INTEGER;
CompareFunc: TStringCompareFunc);
var
IndexLeft, IndexRight: integer;
Pivot, Temp: String;
begin
IndexLeft := LeftIndex;
IndexRight := RightIndex;
Pivot := Strings[(LeftIndex + RightIndex) DIV 2];
repeat
while CompareFunc(Strings[IndexLeft], Pivot) < 0 do inc(IndexLeft);
while CompareFunc(Strings[IndexRight], Pivot) > 0 do dec(IndexRight);
if IndexLeft <= IndexRight then
begin
Temp := Strings[IndexLeft];
Strings[IndexLeft] := Strings[IndexRight];
Strings[IndexRight] := Temp;
inc(IndexLeft);
dec(IndexRight);
end;
until IndexLeft > IndexRight;
if LeftIndex < IndexRight then
QuickSortSL(Strings, LeftIndex, IndexRight, CompareFunc);
if IndexLeft < RightIndex then
QuickSortSL(Strings, IndexLeft, RightIndex, CompareFunc);
end;
procedure TStringListHelper.QuickSortFast;
begin
if Self.Count > 1 then
QuickSortSL(Self, 0, Self.Count - 1, @CompareStringsFast);
end;
function StringList_AnsiCompareStr(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := AnsiCompareStr(List[Index1], List[Index2]);
end;
function StringList_CompareStr(List: TStringList; Index1, Index2: Integer): Integer;
begin
Result := CompareStr(List[Index1], List[Index2]);
end;
function RandomString(ALength: Integer): String;
var
i: Integer;
begin
SetLength(Result, ALength);
Result[1] := char(ord('A') + Random(26));
for i := 2 to ALength do
Result[i] := char(ord('a') + Random(26));
end;
const
N = 200*1000;
CAPACITY = 0; //N;
var
t: TDateTime;
L, L1: TStringList;
i: Integer;
begin
L1 := TStringList.Create;
try
Write('Creating ', Format('%.n', [1.0*N]), ' test strings');
t := Now;
for i := 1 to N do
L1.Add(RandomString(5 + Random(20)));
t := Now-t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
WriteLn;
WriteLn('Capacity = ', CAPACITY);
WriteLn;
Write('Insert sorted (case-sensitive: yes, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := true;
L.UseLocale := true;
L.Sorted := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert sorted (case-sensitive: no, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := true;
L.Sorted := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert sorted (case-sensitive: no, use locale: no )');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := false;
L.Sorted := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
WriteLn;
Write('Insert unsorted, set Sorted to true at end (case-sensitive: yes, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := true;
L.UseLocale := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sorted := true;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert unsorted, set Sorted to true at end (case-sensitive: no, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sorted := true;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert unsorted, set Sorted to true at end (case-sensitive: no, use locale: no )');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := false;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sorted := true;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
WriteLn;
Write('Insert unsorted, call Sort() at end (case-sensitive: yes, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := true;
L.UseLocale := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sort;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert unsorted, call Sort() at end (case-sensitive: no, use locale: yes)');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := true;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sort;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert unsorted, call Sort() at end (case-sensitive: no, use locale: no )');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
L.CaseSensitive := false;
L.UseLocale := false;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.Sort;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
WriteLn;
Write('Insert unsorted, call CustomSort(@CompareStr) at end');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.CustomSort(@StringList_CompareStr);
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
Write('Insert unsorted, call CustomSort(@AnsiCompareStr) at end');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.CustomSort(@StringList_AnsiCompareStr);
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
WriteLn;
Write('Insert unsorted, call helper for sorting at end ');
L := TStringList.Create;
try
L.Capacity := CAPACITY;
t := Now;
for i := 0 to L1.Count-1 do
L.Add(L1[i]);
L.QuickSortFast;
t := Now - t;
WriteLn(' --> ', FormatDateTime('s.zzz', t), ' secs');
finally
L.Free;
end;
finally
L1.Free;
end;
WriteLn;
Write('Press ENTER to close...');
ReadLn;
end.
Re: Zeilenweise Ausgabe optimieren...
@wp_xyz: vielen Dank, das hilft mir enorm weiter bei meinen Überlegungen und Tests.
@m.fuchs: ich habe keine Ahnung, was deine Entscheidung zu dem genannten Beitrag ausgelöst hat - nur Vermutungen.
Daher meine aufrichtige Entschuldigung, falls ich
- meinen Thread selbst umgebogen habe, andere sind viel schlimmer und es war doch ein zur Überschrift verwandtes/abgeleitetes Thema
- jemanden auf den Schlips getreten habe mit dem Satz, daß euch allen klar ist, was für mich die Entdeckung des Tages darstellte
- die KI erwähnt und teilweise zitiert habe, Die Unit ist übrigens meine eigene, ich hatte nur Hilfe/Anstoß bzw habe meinen Sort vom StringArray wiederverwendet
Ich möchte hier nicht mehr weiter kommentieren und werde auch keine Ergebnisse mehr schreiben,
@m.fuchs: ich habe keine Ahnung, was deine Entscheidung zu dem genannten Beitrag ausgelöst hat - nur Vermutungen.
Daher meine aufrichtige Entschuldigung, falls ich
- meinen Thread selbst umgebogen habe, andere sind viel schlimmer und es war doch ein zur Überschrift verwandtes/abgeleitetes Thema
- jemanden auf den Schlips getreten habe mit dem Satz, daß euch allen klar ist, was für mich die Entdeckung des Tages darstellte
- die KI erwähnt und teilweise zitiert habe, Die Unit ist übrigens meine eigene, ich hatte nur Hilfe/Anstoß bzw habe meinen Sort vom StringArray wiederverwendet
Ich möchte hier nicht mehr weiter kommentieren und werde auch keine Ergebnisse mehr schreiben,
- m.fuchs
- Lazarusforum e. V.
- Beiträge: 2844
- Registriert: Fr 22. Sep 2006, 19:32
- OS, Lazarus, FPC: Winux (Lazarus 2.0.10, FPC 3.2.0)
- CPU-Target: x86, x64, arm
- Wohnort: Berlin
- Kontaktdaten:
Re: Zeilenweise Ausgabe optimieren...
Ich weiß jetzt nicht genau, was du mit der Entscheidung meinst, deine Beiträge sind ja alle da und unverändert. Ich habe dir nur einen Hinweis gegeben, wie schon gesagt: irgendwelche negativen Auswirkungen hat das nicht auf dich - das wäre ja auch unsinnig.alfware17 hat geschrieben: @m.fuchs: ich habe keine Ahnung, was deine Entscheidung zu dem genannten Beitrag ausgelöst hat - nur Vermutungen.
0118999881999119725-3
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de
Software, Bibliotheken, Vorträge und mehr: https://www.ypa-software.de