مشاهدة النسخة كاملة : تكتيكات لتحقيق أقصى سرعة لتنفيذ الشيفرة [مترجم]
merouane
25-03-2008, 02:27 PM
السلام عليكم ورحمة الله تعالى وبركاته
قرأت مقالة عن تكتيكات لتحقيق أقصى سرعة لتنفيذ البرنامج في موقع غربي (فرنسي)
و قلت لنفسي لما لا أشاركها مع إخواني في منتدى دلفي للعرب
لكن المشكلة هي أنه إخواني في المشرق - أغلبهم- لا يحسنون اللغة الفرنسية
لذلك روادتني الفكرة، لما لا أجرب وأترجمها لعلها البداية إلى زيادة كسب العلم من مصادر غير العربية و الاستفادة من خبراتهم.
و للعلم لم أنقلها إلا بعد موافقة صاحبها المؤلف (مرفوقة).
وأنوه أنني لست مترجما لذلك كل من رأى سوء ترجمة أو غموض أن يصححه بالتنويه او مراسلة المشرفين
ثم سنصدر نسخا منقحة بعد كل تصحيح (النسخة الحالية 0.1)
أنظر المشاركة اللاحقة
تحياتي :)
merouane
25-03-2008, 02:44 PM
تكتيكات لتحقيق أقصى سرعة لتنفيذ الشيفرة
تحسين الشيفرة هي الممارسة الصحيحة لتغيير شيفرة صحيحة لجعلها أكثر كفاءة. قد تعني التصرف في حجم أو سرعة البرنامج. ولكن في هذه المقالة، سوف نأخذ بعين الحسبان فقط " السرعة ".
يمكننا أن ننظر إلى تحسين مشكلة السرعة على مستويين: الإستراتيجية أو التكتيكية.
على الصعيد الاستراتيجي، ويتم ذلك عن طريق التغييرات التي تعيد تشكيل تصميم كامل للبرنامج والبيانات. وهذا يعني العودة إلى ما يقرب إلى الصفر. ولكن هناك حل بالغ الكفاءة هو شراء (أو تجعل المستخدم الذي يشتكي من البطء يشتري) حاسوب جديد أسرع وأقوى (ههههههه).
وأترك لكم اتخاذ قرار بشأن اعتماد إستراتيجية، وأنا لا أتعامل إلا مع التكتيك. وهذا يعني تغييرات على نطاق صغير، و الذي سوف يتضمن سوى عدد قليل من سطور الشيفرة.
و بعملية حسابية ، عن برامج فورتران، أن 4 ٪ من البرنامج تمثل في المتوسط 50 ٪ من وقت التنفيذ. و هذا بدون شك صحيح بالنسبة لجميع اللغات. سنرى كيفية تحسين هذا الوضع.
أولا لنتحدث عن سوء الفهم الشائع على النحو التالي :
"خفض عدد خطوط الشيفرة يحدد حجم وسرعة التنفيذي فيه."
خطأ!
الأدلة ؟
- تهيئة مجموعة من 10 عناصر :
for i := 1 to 10 do MaTable[i] := 0;
في رأيك، هل الطريقة أسفله ستكون أسرع أم أبطأ ؟
MaTable[1] := 0;
MaTable[2] := 0;
MaTable[3] := 0;
MaTable[4] := 0;
MaTable[5] := 0;
MaTable[6] := 0;
MaTable[7] := 0;
MaTable[8] := 0;
MaTable[9] := 0;
MaTable[10] := 0;
باختبار بواسطة دلفي 7 نجد أن الطريقة الثانية أحسن بنسبة أداء بـ 1.7 : 1 (أسرع بـ 1.7 مرة)
واغتنم هذه الفرصة لإبداء تنويه صغير.
التقنيات التي سأتقدم بها لا تشكل الطريقة التي يتعين تطبيقها بصورة عمياء. القليل من هذه التقنيات المطبقة بصورة عامة تصلح لنقلها مباشرة إلى شيفرتك (محتوى برنامجك). سيكون عليك اختبار والتحقق بأن المجمع (Compiler/compilateur) الذي تملكه يتقبلها. وفي الواقع، بعض التقنيات، والتي تظهر سليمة، يمكن لها أن تقلل من قدر الأداء بعد تجميعها. سأوضح بمثال على هذا، وأذكِّر بنقطة هامة جدا: " الاختبار، الاختبار وإعادة الاختبار".
merouane
25-03-2008, 02:59 PM
هناك ست ركائز تذكرها للحصول على الأداء الجيد. هيا! لنضع الأصابع في الشحم
(Allez ! Mettons les doigts dans le cambouis!)
" تبنَّى منطق دلفي "
لا يساورني أدنى شك في أنك تملك قدرا من المنطق. على كل حال .. علينا أن لا نخشى من الزيادة.
على سبيل المثال، فإن التعبيرات المنطقية التالية هي متكافئة:
(not A) and (not B)
not (A or B)
باختيارنا للتعبير الثاني، هو ‘NOT’. الوقت المُوَفَّر بدون شك طفيف، لكن في حلقة طويلة جدا. سوف نرى.
الخروج من الاختبار في الوقت:
هنا مثال لشفرة محسَّنة:
for i := 0 to High( TableTest ) do
if (TableTest[i] < 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 :
" لنأخذ التعليمة 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
merouane
25-03-2008, 03:13 PM
تحقق من الحلقات
ضع الاختبارات خارج الحلقات:
من السهل الاهتداء إلى الاختبارات التي لا تُعدَّل داخل الحلقات:
for i := 0 to High(TableTest) do begin
if Choix = 0 then TableTest[i] := TableTest[i] + 1
else TableTest[i] := TableTest[i] - 1;
end
و هي نفسها محسنة:
if Choix = 0 then
for i := 0 to High(TableTest) do TableTest[i] := TableTest[i] + 1
else for i := 0 to High(TableTest) do TableTest[i] := TableTest[i] - 1
نسبة الأداء = 1.35 : 1
التحكم في الحلقات:
هذه التقنية تشبه المثال الأول في هذه المقالة أين سيَّرنا بشكل كامل الحلقة من 10 تكرارات. تطبيقيا، لا يمكن تحقيقه من أجل عدد كبير من العناصر أو عندما تكون هذه الأخيرة غير معلومة. و مع ذلك يمكننا أن نحقق هذه التقنية. هذه حلقة عادية:
i:=0;
while i < High(TableTest) do begin
TableTest[i]:= 0;
Inc(i);
end
و مثال لنفس الحلقة معدلة جزئيا:
i:=0;
while i < High(TableTest)-3 do begin
TableTest[i]:= 0;
TableTest[i+1]:= 0;
TableTest[i+2]:= 0;
TableTest[i+3]:= 0;
inc(i,4);
end
{نضبط الحالات الأخيرة}
if i = High(TableTest)-1 then TableTest[High(TableTest)-1] := 0;
if i = High(TableTest)-2 then TableTest[High(TableTest)-2] := 0;
if i = High(TableTest)-3 then TableTest[High(TableTest)-3] := 0
نسبة الأداء = 1.4 : 1
لكن هذه التقنية لا أحبذها. أولا وجدتها فظيعة. وأيضا، يجب فعلا اختبار زيادة الأداء في كل حالة لأنه يمكن أن تتغير حسب العمليات المنفذة. مجمِّع دلفي يقوم عامة بعمل أحسن من هذا الترقيع. اختبرها ولا تستعملها إلا إذا كانت سرعة التنفيذ مرتفعة.
القيمة الحارسة:
مثال عن حلقة بحث تحتوي على اختبار مركب:
NegativeFound := False;
i := 0;
while (not NegativeFound) and (i < High(TableTest)) do begin
if TableTest[i] < 0 then NegativeFound := true;
inc(i);
end
في هذه الشيفرة، مع انه نخرج في الحين، غير أن كل تكرار يختبر (not NegativeFound) و (i < High(TableTest)).
الاختبار TableTest[i] < 0 وظيفته أن يحدد لنا إذا ما كانت القيمة السالبة قد وجدت. الحلقة، إذاً، تنفِّذ 3 اختبارات في كل تكرار.
لكننا نستطيع أن ننفذ اختبار واحد فقط في كل تكرار. و يكون عبر إضافة القيمة المراد البحث عنها إلى العنصر الذي يلي مباشرة نهاية مجال البحث (لا تنسى أن تخصص مكانا لهذا العنصر عند إنشاء الجدول).
هنا، سنعطي قيمة سالبة إلى آخر عنصر بالجدول. إذا لم نجد القيمة السالبة قبل تلك التي وضعناها في الأخير، نعرف أن القيمة التي نبحث عنها لا توجد في الجدول.
بعض سطور من الشيفرة توضح أحسن من شرح طويل:
TableTest[High(TableTest)] := -1; //القيمة الحارسة
NegativeFound := false;
I := 0;
while not TableTest[i] < 0 do inc(i) ;
// نخرج
{ و نتحقق إذا ما قد وجدت القيمة}
if i < High(TableTest) then NegativeFound := true
نسبة الأداء = 1.7 : 1
ضع الحلقة الأكثر نشاطا في الداخل:
عندما تكون الحلقات مركبة، فكر في أي الحلقات ستضعها خارجا وأيها ستضعها في الداخل. المثال التالي قابل للتحسين:
for Col := 0 to 999 do
for Ligne := 0 to 1 do Total := Total + MaTable[ Col, Ligne ];
الحلقة الخارجية تتكرر 1000 مرة. الحلقة الداخلية تتكرر 2 × 1000 = 2000 مرة. إذا لدينا المجموع 3000 تكرار.
نعكس الحلقات:
for Ligne := 0 to 1 do
for Col := 0 to 999 do Total := Total + MaTable[ Col, Ligne ]
نسبة الأداء = 1.9 : 1
في الشيفرة المحسنة الحلقة الخارجية تنفذ مرتين. الحلقة الداخلية تنفذ 2 × 1000 = 2000 مرة. إذا لدينا المجموع 2002 تكرار.
merouane
25-03-2008, 04:43 PM
" حذار من المعطيات التي تتعامل بها "
هذه بعض السطور التي غالبا ما نجدها ضمن شيفرة التي تظهر رسوما متحركة على الشاشة، مثلا:
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;
احترس لإجراءات النظام:
أولا، الوحدة Math تمكننا من استعمال الإجراء ()SinCos الذي هو أسرع مرتين من مناداة ()Sin متبوعة بـ ()Cos:
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;
نسبة الأداء = 1.3 : 1
DegToRad أوضح وأفضل لقراءة الشيفرة، لكنها تأخذ الكثير من الوقت للتنفيذ. ننزعها و نقوم بالتالي:
for Angle := 0 to 360 do begin
SinCos(Angle*0.0174532925199433 ,Sinus, Cosin);
X := Round( Cosin * Hypot );
Y := Round( Sinus * Hypot );
end;
نسبة الأداء = 1.5 : 1 (بالنسبة للمثال الأول)
المعطيات المخبأة:
سرعة الإجراء ()SinCos ليس بسرعة استعمال الجدول. إن تقنية تخبئة المعلومات تعتمد على حفظ - بصورة نظامية - القيَم المستعملة بكثرة في الذاكرة. هنا سنخزن القيَم المثلثية في الجدول:
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;
نسبة الأداء = 7 : 1 (بالنسبة للمثال الأول)
وحدة المعالجة المركزية محسَّنة من أجل 32 بيت:
بدون شك لاحظت أننا عملنا بـ SmallInt في حلقة الحساب. هذا مبرر لأنها كافية لحساب إحداثيات الشاشة. في حين، وحدة المعالجة المركزية تعمل براحة كبيرة عندما تتعامل مع Integer. التعديلات بسيطة:
Var X, Y, Angle, Hypot : Integer;
Sinus, Cosin : Extended;
نسبة الأداء = 9 : 1 (بالنسبة للمثال الأول)
ضبط الزائد عن الحاجة لإجراءات النظام:
نعم في الحقيقة نحن نعمل على الشاشة.
إنها قيمة مثلثية من Extended أي ( 15رقما بعد الفاصلة) تضبط عملية إنزال رجل على القمر، بالنسبة لشاشتي 'm….' لست بحاجة لمثل هذه الدقة. سنقلل من دقة جداول المعطيات المثلثية المخبأة.
و مثلما رأينا أن وحدة معالجة المعطيات تحبذ 32 بيت. إذن و في نفس السياق نحول extendeds إلى Integers.
و في طريقنا نحذف Round، إجراء تابع للنظام مكلف أيضا.
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;
نسبة الأداء = 300 : 1 (بالنسبة للمثال الأول)
أحيانا، مع هذه التقنية، سنحصل على أخطاء صغيرة بخصوص الإحداثيات بسبب الدوران إلى أسفل Div. لكن بالنسبة للرسوم متحركة على الشاشة ستمر بشكل خفي وفي كل الحالات نحن الكاسبون.
تفطَّن لكل شيء:
في رأيكم، ما المزعج في الشيفرة التالية:
Hypothenuse1 := Sqrt( Sqr(CoteA1) + Sqr(CoteB1) );
Hypothenuse2 := Sqrt( Sqr(CoteA2) + Sqr(CoteB2) );
if Hypothenuse1 < Hypothenuse2 then {افعل الأتي};
بكل بساطة إذا Hypothenuse1 < Hypothenuse2 إذن
CoteA1 + CoteB1 < CoteA2 + CoteB2
يمكننا أن نتجنب تكلفة ()Sqrt و ()Sqr عبر التالي:
if CoteA1 + CoteB1 < CoteA2 + CoteB2 then {افعل الأتي};
نسبة الأداء = 10 : 1
merouane
25-03-2008, 04:46 PM
" استعمل SCANLINE "
إذا كانت Canvas.Pixelsملائمة تطبيقيا لمعرفة لون بيكسل منفرد، في حالة ما إذا كنا نعمل على كامل
سطح Bitmap، يجب استعمال Scanline التي هي أكثر فاعلية. في الواقع، فإن الاختناقات المتعلقة بوقت التنفيذ تتواجد غالبا في معالجة Bitmaps.
أوجهكم إلى المثال الجيد الذي قام به Florenth الذي يبدو أنه قام بدراسة المشكلة عدة مرات.
http://www.delphifr.com/codes/BON-USAGE-SCANLINE_43222.aspx
merouane
25-03-2008, 04:48 PM
" تيقظ للأفكار المتلقاة "
مثال: الإزاحة:
كثيرا ما نرى ونسمع أن الإزاحات المزدوجة (Binaires/Binary) سريعة جدا إذا ما أردنا استبدال عملية ضرب أو قسمة بـ 2، 4، 8 الخ:
X := X shl 1
Y := Y shr 2
مع ذلك فوقت التنفيذ هو نفسه بواسطة دلفي 7. إذن نفضل الوضوح:
X := X * 2
Y := Y div 4
نسبة الأداء = 1 : 1
طلبت توضيحا من f0xi الذي يظن أن مجمِّع دلفي ممتاز جدا. هذا هو رده:
" لاسيما وحدات المعالجة المركزية التي أصبحت جيدة.
في حقبة المعالجات وحيدة القلب (monocore)، استعمال shr 1 أو shl 1 أسرع من عملية الضرب أو القسمة. الآن مع وحدات المعالجة مزدوجة (dual)، رباعية (quad)، ثمانية القلب (octo-core)، أصبح سخيف هذا النوع من التحسين.
[ ]
التحسين "المحلي " ليس في الحقيقة سؤالا يُطرح، نحن نتحدث أكثر عن التحسينات " العامة " لمجموع البرنامج و عناصره و أكثر عن منهجية العمل، لأنه إذا كان باستطاعة المجمِّع أن يحسِّن بعض الأوامر ،لا زال غير قادر على أن يحسن مجموعة كاملة من الأوامر."
merouane
25-03-2008, 04:51 PM
" تجنب الكمال "
التحسين، و الأمثل، أحد هذين اللفظين لا يبدو لك معقولا ؟ ( ;
البرنامج هو توازن هش بين وضوحه، سهولة صيانته، وسرعته، و حجمه، و دقته، الخ.
ألمس أحد هذه العناصر و من المرجح سيختل التوازن. ما هو مؤكد، أن تحسين السرعة غالبا ما يتسبب في تقليل وضوح قراءة الشيفرة وتقليل سهولة الصيانة. لذلك، يجب السؤال دائما عن ما هو الأهم. مع الآلات الحديثة نادرا ما تشكل السرعة عائق. على كل حال، سيكون الأمر متروكا لك لحل هذه المعضلة.
الخاتمة:
تعلم استعمال هذه التقنيات عن دراية. في حال تحسين شيفرتك، لا تتوانى عن أن تترك تعليقا عن التقنية التي استعملتها. على العموم إذا كانت التقنيات المستعملة هنا لا تزال صافية، ستكون معيار للبرمجة، لا ؟
يوجد بكل تأكيد تقنيات أخرى أقل أو أكثر فاعلية التي تساعد على تجنب الجداول متعددة الأبعاد إلى غاية استعمال لغة التجميع Assmebler (التحسين في النهاية هو نفسه في لغة التجميع، أوجهكم إلى هذا الموقع www.fastcodeproject.org للحصول على أحسن الإجراءات). لكن هدف هذه المقالة وهو وضعكم على الطريق السوي، وليس إنشاء قائمة فريدة للتقنيات. ****ا أنني وفقت في تقديم النصائح ال******.
وعندما يكون في استطاعتكم مضاعفة سرعة تنفيذ شيفرة إلى 300، ستكونون سعداء أنكم فعلتموها ..
....
شكرا لكل من ساعدني أو شجعني على كتابة هذه المقالة.
------------------------------------------------------------------------------------------ انتهت الترجمة
merouane
25-03-2008, 05:02 PM
في الأخير أذكر أنه إذا كانت هناك تعليقات فلا بد من ذكرها
كما انني لم أترجم تعليقات القراء (التي هي بنظري مهمة) وأتركها لمن يريد ترجمتها
المعذرة لأنني لم أرفق الملفات في أول مشاركة (نسيت :o)
يمكن للمشرف أن ينقلها لأول مشاركة
تحياتي :)
STRELiTZIA
25-03-2008, 07:33 PM
الله يجازيك كل الخير اخي مروان :)
تنسيق PDF احسن بكثير...
اذا كان لديك الوقت اخي ان تدعم الترجمة بامثلة تطبيقية بملفات مصدرية...
تحياتي
delphi4ever
25-03-2008, 07:35 PM
في إنتظار قراءة الدرس ومطالعته،
تقبل تحيات أخوك Delphi4ever على هذا الدرس الرائع والمفيد
وجعله الله في ميزان حسناتك إن شاء الله.
وبالتــــوفيق
و عليكم السلام و رحمة الله و بركاته
أشكرك أخي مروان على هذا الدرس الجيد
و أبدأ تسائلي بالمثال الأول
for i := 1 to 10 do MaTable[i] := 0;
MaTable[1] := 0;
.
.
.
MaTable[10] := 0;
هل هذا يعني أن
MaTable[1] := 0;
.
.
.
MaTable[1000] := 0;
أفضل من
for i := 1 to 1000 do MaTable[i] := 0;
؟
لو سألتني قبل الآن لقلت لا يوجد فرق أما الآن فأتسائل ما السبب الذي جعل الأول أبطا بـ 1.7 من الثاني؟
لقلت لا يوجد فرق
أو الأول أفضل بقليل
Ibrahim elhayik
25-03-2008, 09:00 PM
شكرا علي الجهود
merouane
26-03-2008, 12:34 AM
الله يجازيك كل الخير اخي مروان :)
سبحانه منه الخير كله
تنسيق PDF احسن بكثير...
لذلك أرفقته
اذا كان لديك الوقت اخي ان تدعم الترجمة بامثلة تطبيقية بملفات مصدرية...
ربما في المستقبل .. لا تنسى أننا شركاء فإنني بالمقابل أنتظر منك التطبيق
تحياتي :)
merouane
26-03-2008, 12:37 AM
في إنتظار قراءة الدرس ومطالعته،
تقبل تحيات أخوك Delphi4ever على هذا الدرس الرائع والمفيد
وجعله الله في ميزان حسناتك إن شاء الله.
وبالتــــوفيق
وما الغاية غير الفائدة للناس بالمعرفة، ولنا بالحسنات .. اللهم تقبل
تحياتي :)
merouane
26-03-2008, 12:51 AM
أشكرك أخي مروان على هذا الدرس الجيد
العفو
و أبدأ تسائلي بالمثال الأول
for i := 1 to 10 do MaTable[i] := 0;
MaTable[1] := 0;
.
.
.
MaTable[10] := 0;
هل هذا يعني أن
MaTable[1] := 0;
.
.
.
MaTable[1000] := 0;
أفضل من
for i := 1 to 1000 do MaTable[i] := 0;
؟
لو سألتني قبل الآن لقلت لا يوجد فرق أما الآن فأتسائل ما السبب الذي جعل الأول أبطا بـ 1.7 من الثاني؟
لا حظ أن الكاتب لم يقل ان تلغي For وإنما ضرب مثلا
و التحقق أفضل التأكيدات ، أفرغ بعض الوقت و تحقق من جدول ذو 1000 خانة -- ستفيدنا كثيرا إن فعلتها
أنظر التحقق من اختباري لمثال الكاتب (كل رقم يعني عملية منفذة)
العرض الأول يخص الحلقة For
http://up100.arabsh.com/files/dbq1rbz2chcmwzqw45qv.gif
أما العرض الثاني فهو للتحسين
http://up100.arabsh.com/files/15sn9il6h2swuxcfrheu.gif
ولا تنسى أنه مجرد تحسين من عمل إنسان .. قد تجد بنفسك أحسن من حله
تحياتي :)
merouane
26-03-2008, 12:54 AM
شكرا علي الجهود
العفو
تحياتي :)
bbsafia
26-03-2008, 10:20 PM
الله يعطيك الف عافية
في الحقيقة استفدت كثيرا من هذا الدرس جزاك الله خيرا مروان و يحتاج مني إلى مراجعة أكثر
و لقد خرجت ببعض النتائج و هي
أن استخدام أمر case of أفصل من إستخدام الشرط if then else if then else
و if then else if then else أفضل من if then ; if then ; ... if then
و أن الحلقة الخارجية for من الأفضل أن تكون الأقل من الحلقة الداخلية في حالة الحلقة المركبة.
professor DeXTeR
27-03-2008, 01:46 PM
أحيك من كل قلبي على قوة موضوعك وجهدك يا أخي مروآن
آحترامي لك ..
kml_hmd
27-03-2008, 04:51 PM
شكرا علي الاجتهاد الرائع و المفيد ونتمني لك دوام الصحة و العافية والي المزيد من الاجتهاد
kisokiso
29-03-2008, 01:30 PM
شكرا اخي
بارك الله فيك
merouane
31-03-2008, 11:09 PM
Bbsafia
professor DeXTeR
kml_hmd
kisokiso
العفو و شكرا للردود ، الاحترام والتقدير متبادل
كنت سأسعد كثيرا لو كانت المشاركات تعليقات عن المحتوى ( لأنه يوجد الكثير ما يتوجب الحديث عنه ) أو من الذين يحسنون الفرنسية ترجمة تعليقات القراء في المقال الأصلي.
صراحة أطمح إلى نقاش نرفع فيه المستوى إلى درجة التطوير.. لا أرى أننا سنتقدم أو سنقدم شيئا إذا بقينا على هذه الوتيرة
هذا طبعا إذا أردنا لهذا المنتدى أن يكون مرجعا للغة الدلفي في المنطقة العربية، وأيضا إذا أردنا أن نوفر دعم اللغة العربية أكثر في تطوير البرمجيات.
فقط رأي..
تحياتي :)
Delphawi
16-04-2008, 09:30 AM
باختبار بواسطة دلفي 7 نجد أن الطريقة الثانية أحسن بنسبة أداء بـ 1.7 : 1 (أسرع بـ 1.7 مرة)
كيف تم هذا الاختبار ؟ من اي اداة ؟
وجزاك الله خيرا
merouane
16-04-2008, 08:16 PM
الطريقة المستعملة من طرف الكاتب الأصلي وآخرين هي عبر الإجراء GetTickCount
أنظر SDK Help المرفق مع دلفي عند Win32 Developper's References
أو من موقع ميكروسوفت : http://msdn2.microsoft.com/en-us/library/ms724408.aspx
أظنها تنفع مع جميع لغات البرمجة ضمن Windows
هذا مثال أدرجه أحد المبرمجين
var GTADD, GTDIV : cardinal;
procedure .... ;
begin
GTADD := GetTickCount;
For N := 1 to 10000000 do X := 22 + 8;
GTADD := GetTickCount - GTADD;
GTDIV := GetTickCount;
For N := 1 to 10000000 do X := 22 / 8;
GTDIV := GetTickCount - GTDIV;
caption := format('Add=%d ms / Div=%d ms',[GTADD, GTDIV]);
end;
مع العلم أنه استعمل تكرار من 10000000 للحصول على قيمة قابلة للقياس، لأن GetTickCount ترجع قيمة milliseconds أي جزء من ألف جزء من الثانية (للعمليات الصغيرة قد ينتج 0)
وحسب المعالج processor فمثلا أحدهم قد يحصل على GTADD = 20 ms ، GTDIV = 30 ms بالنسبة للمثال أعلاه وآخر - مثلي - يحصل على GTADD = 15 ms ، GTDIV = 32 ms
.
Delphawi
16-04-2008, 11:14 PM
شكرا مروان
abo-ghadab
17-05-2008, 01:20 AM
اليك شكر نابع من القلب
askander
30-10-2009, 07:30 AM
الف شكر على الترجمة بانتظار المزيد
aboodr
13-01-2010, 05:52 PM
جزاك الله خيرا اخي الكريم وربنا يباركلك
vBulletin® , Copyright ©2008-2012