Entwickler-Ecke

Sonstiges (Delphi) - Geschwindigkeit TStringList


baka0815 - Mo 14.04.08 15:38
Titel: Geschwindigkeit TStringList
Ich experimentiere gerade etwas mit Delphi und Funktionen herum und habe in einer Bibliothek folgendes gefunden:


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
function SearchInList(text : string; list : TStrings): Integer;
var
  j : Integer;
begin
  Result := -1;
  for j := 0 to list.count - 1 do
    IF POS (text, list[j]) = 1 then
    begin
      Result := j;
      Break;
    end;
end;


Was die Funktion macht, ist recht schnell klar: sucht nach dem String "text" in der übergebenen TStrings-Liste.
Ich habe die Schleife extra mit "downto" deklariert, damit die Funktion wirklich immer bis zum Ende durchlaufen muss.

Folgender Code-Ausschnitt soll zur Prüfung der Geschwindigkeit dienen:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
19:
20:
  (...)
  liste := TStringList.Create();

  // Liste füllen
  i2 := 50000;
  for i := 0 to i2 do
  begin
    liste.Add('String #' + IntToStr(i));
  end;

  QueryPerformanceFrequency(n1);

  QueryPerformanceCounter(n2);
  for i := i2 downto 0 do
  begin
    SearchInList('String #' + IntToStr(i), liste);
  end;
  QueryPerformanceCounter(n3);
  diffA := (n3-n2) * 1000 div n1;
  (...)


Für 50.000 Einträge braucht das Konstrukt ganze 70 Sekunden!

Nun hat die abstrakte Klasse TStrings aber eine indexOf()-Methode, die ich sofort getestet habe:

Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
  QueryPerformanceCounter(n2);
  for i := i2 downto 0 do
  begin
    liste.IndexOf('String #' + IntToStr(i));
  end;
  QueryPerformanceCounter(n3);
  diffA := (n3-n2) * 1000 div n1;


Das dauert allein bei 20.000 Einträgen bereits 56 Sekunden, die Funktion von oben benötigt jedoch (nur) 11 Sekunden!

Kann mir jemand erklären, warum die eingebaute Methode indexOf so viel länger braucht?

Wenn ich statt der Klasse TStringList jedoch eine THashedStringList verwende, reden wir von 0,1 Sekunden bei 50.000 Sätzen, die ist also ausser Konkurrenz.

Moderiert von user profile iconChristian S.: Code- durch Delphi-Tags ersetzt


jakobwenzel - Mo 14.04.08 15:56

Die Funktion IndexOf verwendet intern nicht Pos zum vergleichen, sondern AnsiCompareText. Pos ist eigentlich auch inkorrekt, da der Suchtext bei deiner Pos-Version nur am Anfang des Eintrags stehen muss und auch durchaus kürzer sein kann. Bei AnsiCompareText muss jedoch alles komplett gleich sein.

AnsiCompareText braucht für 10000000 Aufrufe 2,14s, gegenüber 79ms bei Pos.

PS: Mitgelieferte VCL-Sourcen sind was tolles :P


Gausi - Mo 14.04.08 15:59

IndexOf sollte auch deutlich schneller sein, wenn die Eigenschaft sorted der Stringlist auf True steht. Den Unterschied zwischen 56 und 11 Sekunden könnte ich mir durch ein Nicht-Abbrechen von IndexOf beim ersten Treffer erkären - aber ich hab da den Source grade nicht parat :nixweiss:


baka0815 - Mo 14.04.08 16:09

Doch, er bricht ab (bin vorher nicht auf die Idee gekommen, selbst in die Sourcen zu gucken).

TStrings führt ein AnsiCompareText() aus mit dem übergebenen Wert und dem per Get() aus der Liste geholten.

TStringList führt indexOf() der Vaterklasse (also TStrings) aus, wenn die Liste nicht sortiert ist.

Wird die TStringList auf Sorted = True gesetzt, dauert das indexOf bei 20.000 EInträgen auch nur noch 0,068 Sekunden.