تكتيكات لتحقيق أقصى سرعة لتنفيذ الشيفرة [مترجم]
#5
" حذار من المعطيات التي تتعامل بها "

هذه بعض السطور التي غالبا ما نجدها ضمن شيفرة التي تظهر رسوما متحركة على الشاشة، مثلا:
كود :
[COLOR=Blue]Var X, Y, Angle, Hypot : Smallint; for Angle := 0 to 360 do begin X := Round( cos(DegToRad(Angle)) * Hypot ); Y := Round( sin(DegToRad(Angle)) * Hypot ); end; [/COLOR]
احترس لإجراءات النظام:

أولا، الوحدة Math تمكننا من استعمال الإجراء ()SinCos الذي هو أسرع مرتين من مناداة ()Sin متبوعة بـ ()Cos:
كود :
[COLOR=Blue]Var X, Y, Angle, Hypot : Smallint Sinus, Cosin : Extended; for Angle := 0 to 360 do begin SinCos(DegToRad(Angle) ,Sinus, Cosin); X := Round( Cosin * Hypot ); Y := Round( Sinus * Hypot ); end; [/COLOR]
نسبة الأداء = 1.3 : 1

DegToRad أوضح وأفضل لقراءة الشيفرة، لكنها تأخذ الكثير من الوقت للتنفيذ. ننزعها و نقوم بالتالي:
كود :
[COLOR=Blue]for Angle := 0 to 360 do begin SinCos(Angle*0.0174532925199433 ,Sinus, Cosin); X := Round( Cosin * Hypot ); Y := Round( Sinus * Hypot ); end;[/COLOR]
نسبة الأداء = 1.5 : 1 (بالنسبة للمثال الأول)

المعطيات المخبأة:

سرعة الإجراء ()SinCos ليس بسرعة استعمال الجدول. إن تقنية تخبئة المعلومات تعتمد على حفظ - بصورة نظامية - القيَم المستعملة بكثرة في الذاكرة. هنا سنخزن القيَم المثلثية في الجدول:
كود :
[COLOR=Blue]Var //متغيرات عامة MonCos : array[0..360] of Extended; // جدول مخبأ MonSin : array[0..360] of Extended; // جدول مخبأ procedure TForm1.FormCreate(Sender: TObject); var Angle : Integer; Sinus, Cosin : Extended; begin for Angle := 0 to 360 do begin SinCos(Angle*0.0174532925199433 ,Sinus, Cosin); MonSin[ Angle ] := Sinus; // إنشاء جدول مخبأ MonCos[ Angle ] := Cosin; end; ... for Angle := 0 to 360 do begin X := Round( MonCos[ Angle ] * Hypot ); Y := Round( MonSin[ Angle ] * Hypot ); end; [/COLOR]
نسبة الأداء = 7 : 1 (بالنسبة للمثال الأول)

وحدة المعالجة المركزية محسَّنة من أجل 32 بيت:

بدون شك لاحظت أننا عملنا بـ SmallInt في حلقة الحساب. هذا مبرر لأنها كافية لحساب إحداثيات الشاشة. في حين، وحدة المعالجة المركزية تعمل براحة كبيرة عندما تتعامل مع Integer. التعديلات بسيطة:
كود :
[COLOR=Blue]Var X, Y, Angle, Hypot : Integer; Sinus, Cosin : Extended;[/COLOR]
نسبة الأداء = 9 : 1 (بالنسبة للمثال الأول)

ضبط الزائد عن الحاجة لإجراءات النظام:

نعم في الحقيقة نحن نعمل على الشاشة.

إنها قيمة مثلثية من Extended أي ( 15رقما بعد الفاصلة) تضبط عملية إنزال رجل على القمر، بالنسبة لشاشتي 'm….' لست بحاجة لمثل هذه الدقة. سنقلل من دقة جداول المعطيات المثلثية المخبأة.

و مثلما رأينا أن وحدة معالجة المعطيات تحبذ 32 بيت. إذن و في نفس السياق نحول extendeds إلى Integers.

و في طريقنا نحذف Round، إجراء تابع للنظام مكلف أيضا.
كود :
[COLOR=Blue]Var // متغيرات عامة MonCosInt : array[0..360] of Integer; // جدول مخبأ MonSinInt : array[0..360] of Integer; // جدول مخبأ procedure TForm1.FormCreate(Sender: TObject); var Angle : Integer; Sinus, Cosin : Extended; begin for Angle := 0 to 360 do begin SinCos(Angle*0.0174532925199433 ,Sinus, Cosin); MonSinInt[ Angle ] := Round( Sinus * 1000 ); MonCosInt[ Angle ] := Round( Cosin * 1000 ); end; ... for Angle := 0 to 360 do begin X := MonCosInt[ Angle ] * Hypot div 1000; Y := MonSinInt [ Angle ] * Hypot div 1000; end; [/COLOR]
نسبة الأداء = 300 : 1 (بالنسبة للمثال الأول)

أحيانا، مع هذه التقنية، سنحصل على أخطاء صغيرة بخصوص الإحداثيات بسبب الدوران إلى أسفل Div. لكن بالنسبة للرسوم متحركة على الشاشة ستمر بشكل خفي وفي كل الحالات نحن الكاسبون.

تفطَّن لكل شيء:

في رأيكم، ما المزعج في الشيفرة التالية:
كود :
[COLOR=Blue]Hypothenuse1 := Sqrt( Sqr(CoteA1) + Sqr(CoteB1) ); Hypothenuse2 := Sqrt( Sqr(CoteA2) + Sqr(CoteB2) ); if Hypothenuse1 < Hypothenuse2 then {افعل الأتي}; [/COLOR]
بكل بساطة إذا Hypothenuse1 < Hypothenuse2 إذن
CoteA1 + CoteB1 < CoteA2 + CoteB2
يمكننا أن نتجنب تكلفة ()Sqrt و ()Sqr عبر التالي:
كود :
[color=Blue]if CoteA1 + CoteB1 < CoteA2 + CoteB2 then {افعل الأتي};[/color]
نسبة الأداء = 10 : 1
الرد


الردود في هذا الموضوع
تكتيكات لتحقيق أقصى سرعة لتنفيذ الشيفرة [مترجم] - بواسطة merouane - 25-03-2008, 03:43 PM

التنقل السريع :


يقوم بقرائة الموضوع: بالاضافة الى ( 1 ) ضيف كريم