Einzelnen Beitrag anzeigen

kaju74

Registriert seit: 22. Okt 2003
185 Beiträge
 
#1

Geschwindigkeit einer Rekursion unter D2010 erhöhen

  Alt 10. Mär 2010, 08:37
Hallo.

Ich habe hier ein kleines Verständnisproblem, warum folgender Code extrem langsam wird, wenn es viele (XML) Unterelemente gibt:

Delphi-Quellcode:
function TXmlDocument.Content: string;

const
  CrLf = #13#10;
  Idnt = #32#32;

{ Expand }

  function Expand(const Str, Indent: string; const Elements: TXmlElements): string;
  var
    i: Integer;
    Content: string;
    SmartEnd: Boolean;
  begin
    Result := Str;
    for i := 0 to Elements.Count - 1 do
    begin
      Result := Result + Indent + '<' + Elements[i].Name;
      Content := Trim(Elements[i].Content);
      SmartEnd := not((Content <> '') or (Elements[i].Elements.Count > 0));
      if not(SmartEnd) then
        Result := Result + '>' + Content;
      if Elements[i].Elements.Count > 0 then
        Result := Expand(Result + CrLf, Indent + Idnt, Elements[i].Elements) + Indent;
      if not(SmartEnd) then
        Result := Result + Format('</%s>', [Elements[i].Name])
      else
        Result := Result + '/>';
      Result := Result + CrLf;
    end;
  end;

begin
  Result := '<?xml version="1.0" encoding="utf-8" ?>' + #13#10 + Expand('', '', Elements);
end;
Hierbei handelt es sich um eine kleine Routine, die rekursiv alle Xml-Elemente durchgeht und einen String
mit dem kompletten Inhalt zurückliefert. Bei einem Baum von 100 Knoten mit jeweils 50 Unterknoten braucht die
Routine auf meinem Rechner stolze 18 Sekunden.

Schritt1: String durch AnsiString ersetzen

Da ich derzeit sowie keine Unicode Xml-Dateien unterstütze und brauche, spare ich mir die ganzen Umwandlungen
und ersetze String durch AnsiString:

Delphi-Quellcode:
function TXmlDocument.Content: AnsiString;

const
  CrLf: AnsiString = #13#10;
  Idnt: AnsiString = #32#32;

{ Expand }

  function Expand(const Str, Indent: AnsiString; const Elements: TXmlElements): AnsiString;
  var
    i: Integer;
    Content: AnsiString;
    SmartEnd: Boolean;
  begin
    Result := Str;
    for i := 0 to Elements.Count - 1 do
    begin
      Result := Result + Indent + '<' + AnsiString(Elements[i].Name);
      Content := AnsiString(Trim(Elements[i].Content));
      SmartEnd := not((Content <> '') or (Elements[i].Elements.Count > 0));
      if not(SmartEnd) then
        Result := Result + '>' + Content;
      if Elements[i].Elements.Count > 0 then
        Result := Expand(Result + CrLf, Indent + Idnt, Elements[i].Elements) + Indent;
      if not(SmartEnd) then
        Result := Result + AnsiString(Format('</%s>', [Elements[i].Name]))
      else
        Result := Result + '/>';
      Result := Result + CrLf;
    end;
  end;

begin
  Result := '<?xml version="1.0" encoding="utf-8" ?>' + #13#10 + Expand('', '', Elements);
end;
Somit komme ich von ~18 Sekunden runter auf ~8 Sekunden. Nun habe ich aber folgendes Phänomen, das ich
nicht so ganz erklären kann:

Ersetze ich die beiden Konstanten am Anfang des Codes durch:

Delphi-Quellcode:
const
  CrLf: '';
  Idnt: '';
Werden aus den ~8 Sekunden schlanke 0,75 Sekunden (und aus den urspünglichen 18 Sekunden für Unicode etwa 4!).

WARUM???

Was kann ich tun, um trotzdem CarriageReturn/Linefeeds und Spaces in meiner Ausgabe zu erhalten, ohne das die
Geschwindigkeit wieder zusammenbricht?

Vielen Dank & Gruß,
kaju
  Mit Zitat antworten Zitat