• 0
ORWA

عشر نصائح لتحسين حجم وسرعة تطبيقات دلفي

سؤال

عندما بدأت كتابة السطور كان يفترض أنني اترجم المقالة من موقع About .

الرابط الاصلي : http://delphi.about.com/od/objectpascalide/a/speedsize.htm

ولكني بعدها أقحمت أفكاري الخاصة وأمثلتي عليها على كل حال أعتقد انني أحتفظت بمعظم العناوين .

عشر نصائح لتحسين حجم وسرعة تطبيقات دلفي

رؤية عروة عيسى . 17/3/2005

ما سأذكره في هذه العجالة هو مجموعة أفكار مفيدة لتحسين حجم وسرعة برامج دلفي .

بداية , فإن تحسين المشروع لأبعد حد (Optimization) يعتبر من الأمور المهمة والمرغوبة في هندسة البرمجيات بشكل عام , ولكن أحذر ؟

فهي دائما كانت في مواجهة أمور أخرى بالغه الأهمية مثل الإستقرارية (stability) والتوسعية (extensibility) , التي تجبرنا أحيانا على غض الطرف قليلا عن الاداء مقابل بعض المكاسب الأخرى (كما قلت في مقالة البرمجة الغرضية التوجه جاءت الـOOP بأفكار التوسعية ولم تعطي الأولوية رقم 1 للأداء ."لاحظ أن C أسرع من C++ كما هو معروف , رغم أن الأخيرة هي الداعمة للـoop , ولكن من المؤكد ان بناء تطبيقات ضخمة وإمكانية إعادة إستخدام الشفرة من نتائج الoop الأساسية ") .

المهم الآن . .. موضوعنا اليوم عن الاداء . مبدأيا السرعة والحجم , رغم وجود امور مهمة اخرى في إدارة الذاكرة مثلا ولكن لن تكون محور الحديث .

يتولى مترجم دلفي في معظم الاحيان إجراء التحسينات(optimimization) على المشروع , ولكن ذلك قد لا يكون كافيا في كثير من الاحيان .

هذه بعض الأفكار التي يمكنك وضعها بالحسبان عند تطوير تطبيقات دلفي يراعى فيها الحصول على ملفات صغيرة الحجم سريعة التنفيذ :

*************************************

1- حافظ على نظافة شفرتك :

ربما يصعب إلى حد ما الجزم فيما إذا كانت الشفرة نظيفة اولا , ولايمكن تحديد ذلك دون التعمق في آلية تنفيذ الامور من الخلف , قد لاتستطيع دائما الجزم أي شفرة انظف من الثانية ولكن أظن أن ذلك سيكون واضحا في كثير من الحالات :

راقب الشفرتين التاليتين

function calc(a,b:integer):boolean;
var c1,c2,c3,c:integer;
r:boolean;
begin
c1:=a*b;
c2:=a+b;
c3:=a-b;
c:=c1+c2+c3;
if c>50 then
r:=true
else
r:=false;

result:=r;
end;

وهذا يقوم بنفس الوظيفة :

function calc(a,b:integer):boolean;
begin
result:=((a*b)+(a*2))>50;
end;

من برأيك الشفرة الأفضل , وأي منهما أسرع بالتنفيذ ,

هل لاحظت ان عدد المتحولات الإضافي سيحجز أمكنة لاداعي لها بالذاكرة ويستهلك مواردك ويبطيء تنفيذك دون مبرر ؟, . في هذا المثال البسيط لن تجد فرق كبير , لكن لوكنا نتعامل مثلا مع برنامج متحولاته من النوعBitmap بالتأكيد كل واحدة منها ستأخذ حجم كبير جدا في الذاكرة لإدارة الصور المخصصة لها , عندها من الخطورة كتابة هكذا نوع من الشفرات الغير مدروسة .

ملاحظة : من المهم الحفاظ على تسميات واضحة للمتغيرات والعناصر ويفضل تجنب إستخدام التسميات الإفتراضية مثل "Button1" التي تغرقك فيما بعد في بحر من اسماء المكونات المشابهة والتي يصعب معرفة ماذا تمثل كل منها

- يفضل وضع طريقة واحدة واضحة لتسمية المتغييرات , مثلا بداها بحرف يحدد النوع , أو الصنف الاب .. مثلا:

SMessage و SName للمتغيرات النصية (String)

iCount و iRate للمتغيرات الصحيحة ,

Tobject للأصناف .

Frm_Main للنماذج , (لاحظ , البدء ب Frm يسهل عليك التعامل معها لاحقا )

*************************************

2- إستخدم توجيهات المترجم المفيدة :

خذ مثلا التوجية {$O+} .

والذي يعني Optimization On .. تاكد دائما من ان هذا التوجيه مفعل (on)

مع هذا التوجيه سيولد مترجم دلفي شفرة اكثر فاعلية . بالتاكيد ستحصل على بعض الصعوبات الإضافية في التنقيح عند إستخدام مثل هذا توجيه .

*************************************]

3- جرب ترجمة برامجك ب Run_Time Packlages :

ربما تعاملت مسبقا مع رزم المكونات ( packages) تملك هذة الرزم نوعان Run_Time و Design_Time ..

رزم الـ Design_Time هي الرزم الإفتراضية , وهي جيدة ولكنها تحمل حجم إضافي لمعلومات سيتم إستخداما في زمن التصميم فقط , وبالتالي من غير المفيد ان يحمل الملف التنفيذي النهائي هذا الحجم الإضافي وهو لن يستطيع الإستفادة منه في زمن التشغيل .

إستخدام Run_Time Packages في حال توفرت مع المكونات حتما سيحسن حجم الملف وأداءة ,

خذ مثلا المكونات التي تحوي محررات خصائص كالتي يمكنك الوصول إليها من ضابط الكائنات , تخزن معلومات هذه المحررات معها مع عدم الفائدة منها في التطبيق التنفيذي النهائي .

. كما أن إستخدام Run_Time مفيد جدا في حال كان لدينا أكثر من تطبيق يستخدمون نفس المكتبات , حيث يكفي توفرها مرة واحدة لكل التطبيقات التي تستخدمها .

المشكلة الاساسية أنه عند استخدام Run_Time_Packages يجب نشر هذة المكتبات مع التطبيق النهائي وكأنها مكتبات DLL .

مثال : إذا كنت تتبادل كثيرا ملفات مع زملائك اللذين يملكون دلفي على اجهزتهم (أي حتما ستضمن وجود نسخة من مكتبات الأدوات القياسية عندهم ) بإمكانك عندها إرسال تطبيقات صغيرة جدا لهم تعتمد على مكتبات Run_Time .

من قائمة Project -> options ->packages إختر الخيار السفلي :

Build with run time packages

وستلاحظ بعدها أن الملف التنفيذي الناتج غدا صغيرا جدا .

(لاحظ الملف المرفق بالمشاركة , ملف نظامي تماما بحجم 16K دون أي خدع بالشفرة)

*************************************

4 – لاتقم بإنشاء كل النماذج منذ بدء التشغيل

تقوم دلفي إفتراضيا بإنشاء النماذج كلها عند التشغيل ( Create All forms at startup ) , ولكن ذلك سيجعل كل النماذج مخزنة بالذاكرة على الرغم من أننا قد لانستخدمها , أو على الأقل لن نستخدمها معا في وقت واحد .

مثال : قد تقوم بإنشاء نموذج "حول"(About) يحوي صورة جميلة لشعار شركتك , ومعلومات عنك , وبريدك الإلكتروني الخ ..

هذا النموذج (About) سيراه المستخدم مرة في العمر , وبالتالي لايوجد داعي لأن يبقى موجودا بالذاكرة كل مرة تشغل فيها البرنامج خاصة انه قديحوي صور بحجم كبير قد تأخذ حيز من الذاكرة من الأفضل ان يبقى لخدمة امور أكثر اهمية , وهذا ماقد يؤثر على سرعة تطبيقك وإستجابتة .

لذلك بإمكانك خلق الذاكرة الخاصة به لحظة ضغط المستخدم على الزر وتحريرها بعد إغلاق النموذج .

كيف نقوم بذلك :

من قائمة دلفي إختر projects -> options

ستظهر أمامك النافذة السابقة , القسم العلوي يحوي مربع إختيار النموذج الأساسي للمشروع , وتحتة مباشرة ستجد قائمة النماذج لديك تحت عنوان Auto_Create .

بكل بساطة حدد النماذج التي لاتريد ان يتم إنشاءها تبقائيا ثم إضغط على زر (>) الذي ينقلها إلى اللائحة المجاورة . أي أنها ستبقى موجودة ,ولكنها لن تنشأ وتحجز مكان بالذاكرة حتى تقوم بطلب ذلك من شفرتك .

سيلزمك الان سطر إضافي كي تستدعي النموذج (Form) , وهو سطر إنشاء الفورم في الذاكرة :

procedure TForm1.Button1Click(Sender: TObject);
begin
with Tform2.create(nil) do show;
end;

أو

procedure TForm1.Button2Click(Sender: TObject);
var frm2:Tform2;
begin
frm2:=TForm2.Create(Application);
frm2.Show;
end;

ولاتنسى تحرير الذاكرة عند الإغلاق :

form2.free;

*************************************

5- إستخدم توابع النظام (Windows API) بدلا من كتابة شفراتك الخاصة .

لإنها أسرع , وتوفرا كثيرا بالحجم . كما انها حتما مدروسة اكثر من شفراتك مهما تعبت عليها .

مثال :

لنقل التركيز إلى العنصر التالي (مشابة لفعل الزر TAB) يمكننا كتابة شفرة شبيهه بالتالية :

procedure Do_Tabs(Sender: TObject; var Key: Word);
var CtlCount: integer;
begin

 if Key = VK_RETURN then
   if (Sender is twincontrol) then begin // ÊÚÏíá åäÇ

     if (sender as twincontrol).TabOrder = num_of_winControl_parent(sender) - 1 then
     begin
     //  for CtlCount := 0 to (sender as twincontrol).Parent.parent.ControlCount - 1 do
       //  if ((sender as twincontrol).Parent.parent.Controls[CtlCount] is twincontrol) then
if ((sender as twincontrol).Parent.parent.Controls[CtlCount]
as TWinControl).TabOrder=
          //   ((sender as twincontrol).Parent.TabOrder +1) then
            //  (sender as twincontrol).Parent.SetFocus;
     end
     else
     begin
       for CtlCount := 0 to (sender as twincontrol).Parent.ControlCount - 1 do
         if ((sender as twincontrol).Parent.Controls[CtlCount] is twincontrol) then
           if ((sender as twincontrol).Parent.Controls[CtlCount] as twincontrol).TabOrder =
(sender as twincontrol).TabOrder + 1 then
             if (((sender as twincontrol).Parent.Controls[CtlCount] as twincontrol).Enabled)
and (((sender as twincontrol).Parent.Controls[CtlCount] as twincontrol).Visible)
then              begin
               ((sender as twincontrol).Parent.Controls[CtlCount] as twincontrol).SetFocus;
               break;
             end;
     end;

ما رأيك الآن بتجربة هذا , الذي يقوم بأفضل من عمل الشفرة السابقة :

Form1.Perform(WM_NEXTDLGCTL, 0, 0);

خذ مثلا الحجم الصغير الذي سينتج معك عند بنائك لنوافذ المشروع بإستخدام API من نظام التشغيل بدلا من إستخدام مكتبة VCL . بغض النظر عن صعوبة أو سهولة أو الضريبة المتعلقة على ذلك , تعتبر توابع API من أسلحة المبرمج الذي يجب التسلح بها .

*************************************

6- حسن إلى أبعد حد الموارد التي تستخدمها في برنامجك :

مثل الصور والأيقونات وملفات الصوت .. الخ ..

إبتعد عن التنسيقات الغير مضغوطة للصور مثل BMP وإستبدلها ب GIF أو JPEG إن أمكن .

تاكد على كل حال من خصائص أخرى مثل عمق الألوان – لاداعي لإستخدام صورة ب 64K color عندما تكفي صورة ب 256 color .

ينصح بتحويل صور jpeg الأقل من 255 color إلى صور Gif الأصغر حجما .

(راجع مكتبة الادوات للحصول على دعم لصور GIF في العنصر image )

- خدعة صغيرة :

عندما تتعامل مع المكون image في دلفي , فإنك على الغالب لاحظت الخاصية stretch .

هذه الخاصية تقوم بمد الصورة حسب حجم ال image التي تعطيها أياه ,

بإمكانك بالتالي إستخدام صورة تدرج لوني بطول صغير (وليكن مثلا 150 بيكسل) وعرض (1 بيكسل فقط) ثم ضبط خاصية stretch إلى true ومد الصورة على الفورم لتحصل على شكل جميل بحجم صغير .

يفضل في حال كنت تستخدم الصورة نفسها اكثر من مرة في أكثر من مكان أن لا تكرر الصورة نفسها في العنصر image لإن ذلك سيضاعف حجم التخزيم كل مرة , ويعتبرها صورة جديدة , يفضل التعامل مع imageList عوضا عن ذلك , أو تحميل الصورة من الملف (LoadFromFile)

*************************************

7- عندما تستخدم إجرائية او أثنين فقط في وحدة ما , وكانت شفرة الوحدة مفتوحة امامك . قم بنسخ شفرة الإجرائيات اللازمة منها وضعها في برنامج بدلا من إضافة الوحدة إلى قائمة uses .

لإنه بمجرد استخدام أحد الأجرائيات المعرفة ضمنها وإضافتها إلى المشروع سيتم حجز الحجم الكامل لها وتضاف كلها إلى الملف التنفيذي وليس فقط الإجرائيات التي إستخدمناها في المشروع .

يمكنك القيام بهذه الطريقة في الكثير من الحالات .

*************************************

8- خفف من استخدام المكونات إن استطعت وخاصة المكونات اللامرئية non_visual components حيث يمكنك إضافة أكوادها يدويا إلى برنامجك , دون التكلف بوضع العنصر الذي سيجر وراءه عدة وحدات ويشغل حجم ربما لست مضطر لتخسرة .

حتى المكونات العادية يمكنك التخفيف منها لاداعي مثلا لوضع مكون مستعرض الإنترنت على النموذج لمجرد عرض رابط لموقعك بإمكانك بسطر واحد القيام بإستدعاء ال internet explorer من ويندوز وفتح موقعك من خلالة .

*************************************

9- تعلم وأستخدم تقنيات سريعة في شفرتك .

مثل استخدام الاسمبلي المضمن مثلا والذي يكفل لك العمل بسرعة رهيبة .

أو إضافات inline في النسخ الجديدة من دلفي (Delphi 2005 مثلا )

وأحذر تمام الحذر عند الحلقات الطويله (long loops) أو التوابع الكثيرة الإستدعاء , او داخل المؤقتات وغيرها من الامكنة التي يتضاعف فيها الخطأ الصغير ليسبب بطء في التنفيذ لاداعي له .

*************************************

10 – إختر خوارزمية عمل مناسبة .

دائما تذكر "أن يقوم الحاسب بإختيار قيمة من مجموعة قيم , أسرع من أن يقوم بحساب هذه القيمة معظم الأحيان"

مارأيك بجداول الجيب (Sin) والتجب (Cos) التي تستخدم في برامج المحاكاة التي تتطلب سرعة عالية .

أستبدل البحث الخطي مثلا بالبحث الثنائي فهو أسرع حتما

وأخيرا وليس اخرا .. بسّط شفرتك . الشفرة البسيطة أسرع بالتنفيذ , وأصغر بالحجم

الملف المرفق

test.zip

تم تعديل بواسطه ORWA
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

12 إجابة على هذا السؤال .

  • 0

ما شاء الله دائما تتحفنا بافكارك الرائعة

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

بارك الله فيك ياعروة ... على هذة المعلومات القيمة

ولدي سؤال ... انت ذكرت طريقة انشاء فورم في الرن تايم .. حفاظآ على الذاكرة

واريد اعرف بعد ان انتهي من الفورم ... عند الأغلاق ماهي الطريقة الصحيحة لتحريره .... او لا يحتاج ان افعل شي ؟

واكثر لنا من هالمواضيع الطيبة ياعروة ... : )

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

اخي عروة انت مبدع مشاء الله عليك

افكارك دائما تحفه فنيه مشاء الله

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا لكم جميعا ..

عند الأغلاق ماهي الطريقة الصحيحة لتحريره .... او لا يحتاج ان افعل شي ؟ :

نعم يحتاج .. أفضل طريقة هي free

form2.free;

لإنها تختبر الغرض تلقائيا وإذا لم يكن موجود لاتعمل مشاكل (في حال تم تحرير الذاكرة أكثر من مرة) , في حين أنك لوجربت تحرير الغرض أكثر من مرة بإستخدام destroy ستبدأ معك المشاكل

بإمكانك أيضا إستخدام freeandnil()

كان ذلك خطأ مني أني لم أذكرها ... حسنا لقد قمت بإضافتها للمشاركة بالأعلى

تم تعديل بواسطه ORWA
0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا على هذه النصائح...

أحببت أن أقترح تعليقاً على النقطة الرابعة ما يلي:

عند إنشاء الفورم من الأفضل استخدام

if not assigned(form_name) then

form_name = Tform_name.Create(Application);

form_name.Show;

وعند الانتهاء منه استخدام

FreeAndNil(form_name)

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

نسيت ان لي سؤال في هذا الموضوع .... يعني form1.free ... تمام تمام .. : )

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

المشكله احيانا اللى تصادفني ببرامجي

بعضها لما اجربه على win xp يكون عال العال ومافيه اي مشاكل

لكن لما انقل البرنامج لـ win 98 تبدأ المشاكل من رسائل الخطأ المعروفه (عمليه غير شرعيه) وخلافه

خاصة لما يكون في البرنامج أدوات تغير شكل البرنامج

مع محاولاتي لتتبع الكود اللى يسبب الخطأ في win 98

لكن مااستطعت

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

المشكله احيانا اللى تصادفني ببرامجي

بعضها لما اجربه على win xp يكون عال العال ومافيه اي مشاكل

لكن لما انقل البرنامج لـ win 98 تبدأ المشاكل من رسائل الخطأ المعروفه (عمليه غير شرعيه) وخلافه

خاصة لما يكون في البرنامج أدوات تغير شكل البرنامج

مع محاولاتي لتتبع الكود اللى يسبب الخطأ في win 98

لكن مااستطعت

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا Almatrodi .. إقتراحك في مكانه

VB-DELPHI , همم أجزم ان ذلك من أدوات تغيير الشكل وليس من مكونات دلفي القياسية , ربما تستخدم هذه الادوات مكتبات او ملفات ما وتضعها في نظام التشغيل ؟؟ ولن تجد هذه الملفات في win 98 لذلك تبدأ الرسائل ...

ماهو أسم الأدوات , ربما نساعد ؟

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

السلام عليكم

form2.free; تعمل معي في حالة إن الفورم بتحتوي على صورة فقط أما إذا كانت الفورم تحتوي على قاعدة بيانات فيه بتديني مشكلة

أعمل إيه

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

عند التعامل مع الإنشاء والتحرير الديناميكي للنموذج . فإن النموذج لن يكون موجود بالذاكرة حتى يتم طلب ذلك بإستخدام create , لذلك لن تستطيع الوصول لمكونات النموذج الذي لم يتم إنشاءة بعد , وفي الكثير من الحالات التي كنا نضبط فيها بعض عناصر النموذج قبل عرضة يجب أن نسبقها ب تعليمان الإنشاء مثال :

بدلا من :

form2.table.open;
form2.show;

يجب أن تصبح :

with tform2.Create(nil) do
begin
Table1.Open;
show;
end;

أما بالنسبة لإغلاق النموذج , تأكدمن قطع إتصال قاعدة البيانات . مثلا في الحدث onclose :

code]

Table1.Close;

free;

المثال المرفق يوضح ذلك

create_free.zip

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
  • 0

شكرا لك إخي وفقك الله -waf

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .