هناك ست ركائز تذكرها للحصول على الأداء الجيد. هيا! لنضع الأصابع في الشحم
(Allez ! Mettons les doigts dans le cambouis!)
" تبنَّى منطق دلفي "
لا يساورني أدنى شك في أنك تملك قدرا من المنطق. على كل حال .. علينا أن لا نخشى من الزيادة.
على سبيل المثال، فإن التعبيرات المنطقية التالية هي متكافئة:
كود :
[align=center][COLOR=Blue](not A) and (not B)
not (A or B)[/COLOR][/align]
باختيارنا للتعبير الثاني، هو ‘NOT’. الوقت المُوَفَّر بدون شك طفيف، لكن في حلقة طويلة جدا. سوف نرى.
الخروج من الاختبار في الوقت:
هنا مثال لشفرة محسَّنة:
for i := 0 to High( TableTest ) do
if (TableTest < 0) then
NegativeFound := true
وهو حلقة للبحث، حالة شائعة جدا. مبدأ التحسين يرتكز على عدم مواصلة التحقق إذا وجدت النتيجة. لنطبِّق المبدأ:
for i := 0 to High( TableTest ) do begin
if TableTest[i] < 0 then
begin
NegativeFound := true;
;Break
//الخروج حالما وجدت النتيجة
end;
end
هنا، زيادة الأداء ستكون جد متباينة حسب المحتوى. لكن في معظم الحالات، الزيادة ستكون بالغة الأهمية. إذا وضعنا قيمة سالبة في وسط الجدول، يمكننا أن نتوقع وقت التنفيذ سيكون مرتين أسرع. هذا هو ما تأكده الاختبارات.
مثال أخر:
N := Random(101);
…
if (N>=0) and (N<5) then Categorie := 1;
if (N>=5) and (N<20) then Categorie := 2;
if (N>=20) and (N<101) then Categorie := 3;
و نفس الشيفرة محسنة جزئيا:
if (N>=20) then Categorie := 3
// الخروج حالما وجدت النتيجة
else if (N>=5) then Categorie := 2
// الخروج حالما وجدت النتيجة
else Categorie := 1
نسبة الأداء = 1.3 : 1 ويمكننا أن نحقق أكثر..
ترتيب الاختبارات تصاعديا:
if (N<5) then Categorie := 1
else if N<20 then Categorie := 2
else Categorie := 3
نسبة الأداء = 1.9 : 1
- ستقولون لي : " أين المنطق في كل هذا ؟ "
- حسنا، إنه منطق مجمِّع دلفي 7.
لقد قلت لكم " الاختبار، الاختبار وإعادة الاختبار "
هذا المثال يؤكد أهمية عدم الانسياق وراء نصائح التحسين بدون هدى. ما هو صحيح بالنسبة لـ C# ليس بالضرورة بالنسبة لجافا أو الدلفي. بعض التحسينات صحيحة بالنسبة للغة تتدرج الأداء بوجه كبير من لغة أخرى. بالإضافة، ذلك يمكن أن يختلف من نسخة إلى أخرى لنفس المجمِّع. عليك، إذاً، قياس الأداء لأن قواعد اللعبة تتغير بتغييرك للغة، المجمِّع أو نسخة لنفس المجمِّع، المعالج، الذاكرة الحية، المنطقة (حسنا، حسنا، ربما ليس المنطقة)، الخ..
أقتبس من Olivier DAHAN :
[I]
" لنأخذ التعليمة case كمثال. إلى غاية بورلاند باسكال 7 ترتيب أفضل الثوابت من حيث فعالية الشيفرة هي تلك التي تنخفض فيها وتيرة الاستخدام: حالة الأكثر تكرار يجب أن يوضع في الأول، والأقل تكرارا في الأخير. هذه كانت مرتبطة بشيفرة الآلة التي تولِّدها باسكال (سلسلة من المقارنات والقفز من حالة إلى أخرى ، من الأولى إلى الأخيرة). باسكال غرضية التوجه لدلفي تولِّد شيفرة مختلفة جدا، وهنا إمكانية تحسين الفعالية للتعليمة case وهي وضع ثوابت الحالة في ترتيب عددي تصاعدي (وهو ترتيب الإعلان DECLARATION في النوع إذا كان منتقي الحالة من نوع عددي)".
آمل أنه قد أيقظ الشك لديك.
و إلا سأزيد طبقة:
Case of أفضل من If then else :
عوضا عن كتابة:
case N of
20..100 : Categorie := 3;
5..19 : Categorie := 2;
else Categorie := 1;
end
أفضل الصياغة الأسرع بـ 1.5 مرة:
case N of
0..4 : Categorie := 1;
5..19 : Categorie := 2;
else Categorie := 3;
end
الآن، نسبة الأداء = 1.95 : 1
تقريبا ضعف سرعة المثال في البداية. (إنها تدفنها مرة واحدة، لأن case of دائما أوضح من if then else متداخلة).
- في C#: case of و if then else قابلة للمقارنة.
- على العكس، في الجافا if then else أسرع بـ 6 مرات من case of.
- و في فيسوال بازيك، إنها case of الأسرع بـ 4 مرات من if then else (Steve McConnell dixit).
للمنصت، كيف الحال.
استبدال التعبيرات المنطقية المعقدة بجدول:
على سبيل مثال موجز، لنفرض أن لديكم رقم من الفئة (0،1،2،3) للتخصيص إلى غرض حسب عضويتها إلى مجموعة واحدة
أو أكثر A،Bِ،C :
مثال مقتطف من كتاب Steve McConnell : «CODE COMPLETE» وعُدِّل من C++ إلى دلفي.
على العموم، نكتب على الشكل التالي:
if ((N in EnsembleA) and not (N in EnsembleC)) or ((N in EnsembleA) and
(N in EnsembleB) and (N in EnsembleC)) then Categorie := 1
else if ((N in EnsembleB) and not (N in EnsembleA)) or ((N in EnsembleA) and
(N in EnsembleC) and not (N in EnsembleB)) then Categorie := 2
else if (N in EnsembleC) and not (N in EnsembleA) and not (N in EnsembleB)
then Categorie := 3
else Categorie := 0
بالبحث في جدول، مؤكد سوف لن نزيد من وضوح الشيفرة، لكنه لن يكون أكثر غموضا.. على العموم، يمكننا دائما أن نوثِّق الشيفرة بتعليقات و الجدول سيكون أسهل للتعديل عند الضرورة. يصبح لدينا:
type
TTab = array[0..1, 0..1, 0..1] of byte;
const
TableCategorie : TTab = // notB,notC notB,C B,notC B,C
(((0, 3), (2, 2)), // notA
((1, 2), (1, 1))); // A
Categorie := TableCategorie[Ord(N in EnsembleA),
Ord(N in EnsembleB),
Ord(N in EnsembleC)]
نسبة الأداء = 9 : 1