Вопрос

У меня есть функция, которая должна преобразовать ADO Recordset в HTML:

class function RecordsetToHtml(const rs: _Recordset): WideString;

И смета функции включает много широкого конкатенации строки:

   while not rs.EOF do
   begin
      Result := Result+CRLF+
         '<TR>';

      for i := 0 to rs.Fields.Count-1 do
         Result := Result+'<TD>'+VarAsWideString(rs.Fields[i].Value)+'</TD>';

      Result := Result+'</TR>';
      rs.MoveNext;
    end;

С несколькими тысячами результатов функция берет, какой пользователь будет чувствовать, слишком долго запустить. То Дельфи пробоотборник Profiler показывает, что 99.3% времени проводится в расширении конкатенации (@WStrCatN а также @WstrCat).

Может кто-нибудь думать о том, как улучшить широкое согласование Concatenation? Я не думаю, что Delphi 5 имеет какой-то строковый строитель. А также Format не поддерживает Unicode.


И чтобы убедиться, что никто не пытается вырвать: притвориться, что вы реализуете интерфейс:

IRecordsetToHtml = interface(IUnknown)
    function RecordsetToHtml(const rs: _Recordset): WideString;
end;

Обновить один

Я думал об использовании IXMLDOMDocument, чтобы создать HTML как XML. Но тогда я понял, что последний HTML будет xhtml и не html - Тонкий, но важный, разница.

Обновить два

Статья базы знаний Microsoft: Как улучшить производительность конкатенации строки

Это было полезно?

Решение 4

Я нашел лучшее решение. Открытый источник HTMLPARSER. Для Delphi есть помощник TStringBuilder сорт. Он внутренне используется для создания того, что он звонит DomStringS, что на самом деле псевдоним WideString:

TDomString = WideString;

С небольшим количеством возобновления своего класса:

TStringBuilder = class
public
   constructor Create(ACapacity: Integer);
   function EndWithWhiteSpace: Boolean;
   function TailMatch(const Tail: WideString): Boolean;
   function ToString: WideString;
   procedure AppendText(const TextStr: WideString);
   procedure Append(const value: WideString);
   procedure AppendLine(const value: WideString);
   property Length: Integer read FLength;
end;

Муки рутины становится:

while not rs.EOF do
begin
   sb.Append('<TR>');

   for i := 0 to rs.Fields.Count-1 do
      sb.Append('<TD>'+VarAsWideString(rs.Fields[i].Value));

   sb.AppendLine('</TR>');

   rs.MoveNext;
end;

Код тогда чувствителен бежать бесконечно вдальше. Профилирующий шоу много улучшение; то WideString Манипулирование и подсчет длины стали незначительными. На его месте были собственные внутренние операции Fastmm.

Примечания

  1. Приятный улов на ошибке принуждение всех строк в текущую кодовую страницу (VarAsString скорее, чем VarAsWideString)
  2. Некоторые закрывающие теги HTML являются необязательными; опущенные те, которые логически не имеют смысла.

Другие советы

ShareString по своей природе медленно медленно, потому что они были реализованы для совместимости COM и проходят через COM-вызовы. Если вы посмотрите на код, он будет продолжать перераспределить строку и вызовать SYSALLOCSTRINGLEN () & C, которые являются API из OLEAUT32.DLL. Он не использует диспетчер памяти Delphi, но AFAIK он использует Com Memory Manager. Поскольку большинство страниц HTML не используют UTF-16, вы можете получить лучший результат, используя нативный тип строки Delphi и строковый список, хотя вы должны быть осторожны с преобразованием от UTF и фактического кодового управления, а преобразование будет выполнена производительность Отказ Также вы используете функцию VarasString (), которая, вероятно, преобразует вариант на Ансистрая затем преобразуется в ширину. Проверьте, есть ли ваша версия Delphi VARASWIDESTRING () или что-то одинаково, чтобы избежать его или полагаться на автоматическое преобразование Delphi, если вы можете быть уверены, что ваш вариант никогда не будет нулевым.

Да, ваш алгоритм явно в O (n ^ 2).

Вместо того, чтобы возвращать string, попробуйте вернуть TStringList, и замените свой цикл с

   while not rs.EOF do
   begin
      Result.Add('<TR>');

      for i := 0 to rs.Fields.Count-1 do
         Result.Add( '<TD>'+VarAsString(rs.Fields[i].Value)+'</TD>' );

      Result := Result.Add('</TR>');
      rs.MoveNext;
    end;

Затем вы можете сохранить свой Result с использованием TStringList.SaveToFile

Я не могу провести время прямо сейчас, чтобы дать вам точный код.

Но я думаю, что самое быстрое, что вы можете сделать, это:

  1. Структура через все строки и общая их длина также добавляет для дополнительных тегов таблицы, которые вам понадобятся.

  2. Используйте SetString, чтобы выделить одну строку правильной длины.

  3. Петли через все строки снова и используйте Процедура «Перемещение» Чтобы скопировать в строку в правильное место в финальной строке.

Ключевая вещь состоит в том, что многие конкатенации на строку занимают больше времени и дольше из-за постоянного выделения и освобождения памяти. Одиночное распределение будет вашим самым большим временем.

SWIRESTRING не содержит ссылок, любая модификация означает манипулирование строковыми рубами. Если ваш контент не закодирован Unicode, вы можете внутренне использовать родную строку (ссылку, подсчитанную) для объединения строки, а затем преобразуйте его в ShareString. Пример выглядит следующим образом:

var
  NativeString: string;
begin
   // ...
   NativeString := '';

   while not rs.EOF do
   begin
     NativeString := NativeString + CRLF + '<TR>';

     for i := 0 to rs.Fields.Count-1 do
       NativeString := NativeString + '<TD>'+VarAsString(rs.Fields[i].Value) + '</TD>';

     NativeString := NativeString + '</TR>';
     rs.MoveNext;
   end;

   Result := WideString(NativeString);

Я также видел еще один подход: кодируют Unicode для UTF8STRING (как отсчитанный ссылкой), объединяйте их и, наконец, конвертируйте UTF8STRING на WIDESTRING. Но я не уверен, если два UTF8String могут быть объединены напрямую. Также следует учитывать время на кодировке.

Во всяком случае, хотя широко распространенное конкатенация намного медленнее, чем собственные строковые операции. Но это IMO все еще приемлемо. Слишком много тюнинга на такой вещи следует избегать. Серьезно рассмотрение производительности, вы должны затем обновить вашу Delphi по крайней мере в 2009 году. Расходы на покупку инструмента предназначены для долгосрочных дешевле, чем делать тяжелые хаки на старом Delphi.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top