سؤال

لدي وظيفة من الوظيفة هي تحويل اللغط 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;

مع بضع آلاف من النتائج ، تأخذ الوظيفة ، وما يشعر به أي مستخدم ، طويل جدًا بحيث لا يمكن تشغيله. ال دلفي أخذ عينات من البروفيلر يدل على أن 99.3% من الوقت يقضي في تسلسل العرض (@WStrCatN و @WstrCat).

هل يمكن لأي شخص أن يفكر في طريقة لتحسين تسلسل العرض؟ لا أعتقد أن Delphi 5 لديه أي نوع من باني سلسلة. و Format لا يدعم Unicode.


وللتأكد من أن لا أحد يحاول أن يخرج: التظاهر بأنك تقوم بتنفيذ الواجهة:

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

تحديث واحد

فكرت في استخدام IXMLDOMDocument, ، لبناء HTML مثل XML. ولكن بعد ذلك أدركت أن HTML النهائي سيكون xhtml و لا html - اختلاف خفي ولكن مهم.

تحديث اثنين

مقالة قاعدة المعرفة Microsoft: كيفية تحسين أداء سلسلة السلسلة

هل كانت مفيدة؟

المحلول 4

لقد وجدت أفضل حل. المصدر المفتوح htmlparser لدلفي ، لديه مساعد 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 اختيارية ؛ حذفت تلك التي لا معنى لها منطقيا.

نصائح أخرى

تكون WideString بطيئة بطبيعتها لأنها تم تنفيذها من أجل توافق COM وتخوض مكالمات COM. إذا نظرت إلى الكود ، فسيستمر ذلك في إعادة تخصيص السلسلة واستدعاء sysallocstringlen () & c والتي هي واجهات برمجة التطبيقات من OLEAUT32.DLL. لا يستخدم Delphi Memory Manager ولكن Afaik يستخدم Com Memory Manager. نظرًا لأن معظم صفحات HTML لا تستخدم UTF-16 ، فقد تحصل على نتيجة أفضل باستخدام نوع سلسلة Delphi الأصلي وقائمة سلسلة ، على الرغم من أنك يجب أن تكون حذراً بشأن التحويل من UTF و Codepage الفعلي ، وسيقوم التحويل بخفض الأداء أيضًا . كما أنك تستخدم وظيفة varasstring () التي ربما تحول متغير إلى Ansistring ثم تحول إلى widestring. تحقق مما إذا كان الإصدار الخاص بك من 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. حلقة من خلال جميع الأوتار مرة أخرى واستخدامها إجراء "الحركة" لنسخ إلى السلسلة إلى المكان المناسب في السلسلة النهائية.

الشيء الرئيسي هو أن العديد من التسلسل لسلسلة يستغرق وقتًا أطول وأطول بسبب تخصيص الذاكرة المستمرة وتحريرها. سيكون تخصيص واحد هو أكبر وقت لك.

لا يتم احتساب WideString ، أي تعديل يعني معالجة السلسلة. إذا لم يتم ترميز المحتوى الخاص بك, ، يمكنك استخدام السلسلة الأصلية داخليًا (المرجع المرجعي) لتسلسل السلسلة ثم تحويلها إلى عرض واسع. مثال على النحو التالي:

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);

لقد رأيت أيضًا نهجًا آخر: encode Unicode على UTF8String (كما تم حساب المرجع) ، وحلها وأخيراً تحويل UTF8String إلى widestring. لكنني لست متأكدًا ، إذا كان يمكن تسلسل اثنين من UTF8String مباشرة. يجب أيضًا مراعاة الوقت في الترميز.

على أي حال ، على الرغم من أن تسلسل العرض هو أبطأ بكثير من عمليات السلسلة الأصلية. لكنه لا يزال IMO مقبولًا. يجب تجنب الكثير من الضبط على هذا النوع من الأشياء. بالنظر إلى الأداء بجدية في الأداء ، يجب عليك بعد ذلك ترقية Delphi إلى عام 2009. تكاليف شراء الأداة هي لأرخص طويلة الأجل من القيام بالاختراقات الثقيلة على Delphi القديم.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top