تحسين البرنامج
في علم الحاسوب ، يُعرف تحسين البرامج أو تحسين الشيفرة أو تحسين البرمجيات بأنه عملية تعديل نظام برمجي لجعل جانب معين منه يعمل بكفاءة أكبر أو يستهلك موارد أقل. [ 1 ] بشكل عام، يمكن تحسين برنامج الحاسوب بحيث يُنفذ بسرعة أكبر، أو لجعله قادرًا على العمل بذاكرة تخزين أقل أو موارد أخرى أقل، أو استهلاك طاقة أقل.
ملخص
على الرغم من أن مصطلح "التحسين" مشتق من "الأمثل"، [ 2 ] إلا أن الوصول إلى نظام مثالي تمامًا نادر الحدوث عمليًا، ويُشار إلى ذلك بالتحسين الفائق . [ 3 ] يركز التحسين عادةً على تحسين النظام وفقًا لمقياس جودة محدد بدلًا من جعله مثاليًا بشكل عام. غالبًا ما يؤدي هذا إلى مفاضلات، حيث قد يأتي تحسين أحد المقاييس على حساب مقياس آخر. أحد الأمثلة الشائعة هو المفاضلة بين المساحة والوقت ، حيث يمكن أن يؤدي تقليل وقت تنفيذ البرنامج إلى زيادة استهلاكه للذاكرة. في المقابل، في الحالات التي تكون فيها الذاكرة محدودة، قد يُعطي المهندسون الأولوية لخوارزمية أبطأ لتوفير المساحة. نادرًا ما يوجد تصميم واحد يتفوق في جميع الحالات، مما يتطلب من المبرمجين إعطاء الأولوية للسمات الأكثر صلة بالتطبيق قيد الاستخدام. تشمل مقاييس البرمجيات الإنتاجية، وزمن الاستجابة ، واستخدام الذاكرة المتطايرة ، والتخزين الدائم ، واستخدام الإنترنت ، واستهلاك الطاقة ، وتآكل الأجهزة . المقياس الأكثر شيوعًا هو السرعة.
علاوة على ذلك، يتطلب تحقيق الأمثلية المطلقة في كثير من الأحيان جهداً يفوق بكثير الفوائد المرجوة. ونتيجة لذلك، عادةً ما تتباطأ عمليات التحسين بمجرد تحقيق تحسينات كافية. ولحسن الحظ، غالباً ما تتحقق مكاسب كبيرة في المراحل الأولى من عملية التحسين، مما يجعل التوقف قبل الوصول إلى مرحلة تناقص العائد أمراً عملياً .
مستويات التحسين
يمكن إجراء التحسين على مستويات متعددة. عادةً ما يكون للمستويات العليا تأثير أكبر، ويصعب تغييرها لاحقًا في المشروع، مما يتطلب تغييرات جوهرية أو إعادة كتابة كاملة إذا لزم الأمر. لذا، يمكن أن يتم التحسين عادةً من خلال الصقل التدريجي من الأعلى إلى الأدنى، حيث تكون المكاسب الأولية أكبر وتتحقق بجهد أقل، بينما تكون المكاسب اللاحقة أصغر وتتطلب جهدًا أكبر. مع ذلك، في بعض الحالات، يعتمد الأداء العام على أداء أجزاء منخفضة المستوى جدًا من البرنامج، وقد يكون للتغييرات الطفيفة في مرحلة متأخرة أو النظر المبكر في التفاصيل الدقيقة تأثير بالغ. عادةً ما يُولى بعض الاهتمام للكفاءة طوال المشروع - على الرغم من أن هذا يختلف اختلافًا كبيرًا - ولكن غالبًا ما يُعتبر التحسين الرئيسي صقلًا يُجرى في وقت متأخر، إن أُجري أصلًا. في المشاريع طويلة الأمد، توجد عادةً دورات من التحسين، حيث يكشف تحسين جانب ما عن قصور في جانب آخر، وعادةً ما يتم تقليص هذه الدورات عندما يكون الأداء مقبولًا أو عندما تصبح المكاسب ضئيلة جدًا أو مكلفة. تشمل أفضل ممارسات التحسين خلال دورات التطوير التكرارية المراقبة المستمرة لمشاكل الأداء إلى جانب اختبار الأداء المنتظم. [ 4 ] [ 5 ]
بما أن الأداء جزء لا يتجزأ من مواصفات البرنامج - فالبرنامج البطيء لدرجة تجعله غير قابل للاستخدام لا يصلح للغرض المطلوب: قد تكون لعبة فيديو بمعدل 60 هرتز (إطارات في الثانية) مقبولة، لكن 6 إطارات في الثانية تُعدّ متقطعة بشكل غير مقبول - فإن الأداء يُؤخذ في الاعتبار منذ البداية، لضمان قدرة النظام على تقديم أداء كافٍ، ويجب أن تتمتع النماذج الأولية بأداء مقبول تقريبًا لضمان أن النظام النهائي (مع التحسين) سيحقق أداءً مقبولًا. يُغفل هذا الأمر أحيانًا لاعتقادهم بإمكانية إجراء التحسين لاحقًا، مما ينتج عنه أنظمة أولية بطيئة للغاية - غالبًا بفارق عشرة أضعاف أو أكثر - وأنظمة فاشلة في نهاية المطاف لأنها لا تستطيع من الناحية المعمارية تحقيق أهداف الأداء، مثل Intel 432 (1981)؛ أو أنظمة استغرقت سنوات من العمل لتحقيق أداء مقبول، مثل Java (1995)، التي لم تحقق أداءً يُضاهي أداء الكود الأصلي إلا مع HotSpot (1999). [ 6 ] يمكن أن تكون درجة تغير الأداء بين النموذج الأولي ونظام الإنتاج، ومدى قابليته للتحسين، مصدرًا مهمًا للشك والمخاطر.
مستوى التصميم
على أعلى مستوى، يُمكن تحسين التصميم لتحقيق الاستخدام الأمثل للموارد المتاحة، مع مراعاة الأهداف والقيود والاستخدام/الحمل المتوقع. يؤثر التصميم المعماري للنظام بشكل كبير على أدائه. على سبيل المثال، يُحسّن النظام الذي يعتمد على زمن استجابة الشبكة (حيث يُعد زمن استجابة الشبكة القيد الرئيسي على الأداء العام) لتقليل عدد مرات الاتصال بالشبكة، ويفضل أن يتم إرسال طلب واحد فقط (أو لا يتم إرسال أي طلبات، كما في بروتوكول الدفع ) بدلاً من عدة عمليات إرسال واستقبال. يعتمد اختيار التصميم على الأهداف: عند تصميم مُترجم ، إذا كانت سرعة الترجمة هي الأولوية الرئيسية، فإن المُترجم أحادي المرور أسرع من المُترجم متعدد المرور (بافتراض نفس العمل)، ولكن إذا كانت سرعة إخراج الكود هي الهدف، فإن المُترجم متعدد المرور الأبطأ يُحقق الهدف بشكل أفضل، على الرغم من أنه يستغرق وقتًا أطول. يتم اختيار المنصة ولغة البرمجة على هذا المستوى، وغالبًا ما يتطلب تغييرها إعادة كتابة كاملة، على الرغم من أن النظام المعياري قد يسمح بإعادة كتابة بعض المكونات فقط - على سبيل المثال، بالنسبة لبرنامج بايثون، يمكن إعادة كتابة الأجزاء الحساسة للأداء بلغة C. في النظام الموزع، يتم اختيار البنية ( عميل-خادم ، نظير إلى نظير ، إلخ) على مستوى التصميم، وقد يكون من الصعب تغييرها، خاصة إذا لم يكن من الممكن استبدال جميع المكونات بشكل متزامن (مثل العملاء القدامى).
الخوارزميات وهياكل البيانات
بعد وضع تصميم شامل، يأتي اختيار الخوارزميات وهياكل البيانات الفعّالة ، ثم التنفيذ الفعّال لهذه الخوارزميات وهياكل البيانات. بعد التصميم، يؤثر اختيار الخوارزميات وهياكل البيانات على الكفاءة أكثر من أي جانب آخر من جوانب البرنامج. عمومًا، يصعب تغيير هياكل البيانات مقارنةً بالخوارزميات، نظرًا لاستخدام افتراضات هيكل البيانات وافتراضات أدائها في جميع أنحاء البرنامج، مع إمكانية تقليل ذلك باستخدام أنواع البيانات المجردة في تعريفات الدوال، وحصر تعريفات هياكل البيانات الملموسة في أماكن قليلة. قد تتطلب التغييرات في هياكل البيانات المرتبطة بقاعدة البيانات ترحيل المخطط وتغييرات معقدة أخرى في البرامج أو البنية التحتية. [ 7 ]
بالنسبة للخوارزميات، يتمثل هذا بشكل أساسي في ضمان أن تكون الخوارزميات ذات تعقيد ثابت O(1)، أو لوغاريتمي O(log n )، أو خطي O( n )، أو في بعض الحالات لوغاريتمي خطي O( n log n ) في المدخلات (سواءً من حيث المساحة أو الوقت). الخوارزميات ذات التعقيد التربيعي O( n² ) لا تتوسع، وحتى الخوارزميات الخطية تُسبب مشاكل إذا تم استدعاؤها بشكل متكرر، وعادةً ما يتم استبدالها بخوارزميات ذات تعقيد ثابت أو لوغاريتمي إن أمكن .
بغض النظر عن رتبة النمو التقاربية، فإن العوامل الثابتة مهمة: قد تكون الخوارزمية الأبطأ تقاربياً أسرع أو أصغر حجماً (لأنها أبسط) من الخوارزمية الأسرع تقاربياً عندما تواجه كلتاهما مدخلات صغيرة، وهو ما قد يحدث في الواقع. غالباً ما توفر الخوارزمية الهجينة أفضل أداء، نظراً لتغير هذه المفاضلة بتغير الحجم.
إحدى التقنيات العامة لتحسين الأداء هي تجنب العمليات غير الضرورية. ومن الأمثلة الجيدة على ذلك استخدام مسار سريع للحالات الشائعة، مما يحسن الأداء بتجنب العمليات غير الضرورية. على سبيل المثال، استخدام خوارزمية بسيطة لتنسيق النصوص اللاتينية، واللجوء إلى خوارزمية معقدة فقط للنصوص المعقدة، مثل ديفاناغاري . ومن التقنيات المهمة الأخرى التخزين المؤقت، وخاصةً التخزين المؤقت للذاكرة ، الذي يتجنب العمليات الحسابية المتكررة. ونظرًا لأهمية التخزين المؤقت، غالبًا ما توجد مستويات متعددة منه في النظام، مما قد يُسبب مشاكل في استخدام الذاكرة، ومشاكل في دقة البيانات بسبب قِدم البيانات المخزنة مؤقتًا.
مستوى شفرة المصدر
إلى جانب الخوارزميات العامة وتطبيقها على جهاز افتراضي، يمكن لخيارات محددة على مستوى شفرة المصدر أن تُحدث فرقًا كبيرًا. على سبيل المثال، في مُجمِّعات لغة C القديمة، كان استخدام حلقة تكرارية غير مشروطة أبطأ من استخدام حلقة تكرارية غير مشروطة، لأن الحلقة التكرارية غير المشروطة كانت تُقيَّم ثم تتضمن قفزة شرطية للتحقق من صحتها، بينما كانت الحلقة التكرارية غير مشروطة. يمكن اليوم إجراء بعض التحسينات (مثل هذا التحسين) من خلال مُجمِّعات مُحسِّنة . يعتمد هذا على لغة المصدر ولغة الآلة المستهدفة والمُجمِّع، وقد يكون من الصعب فهمه أو التنبؤ به، كما أنه يتغير بمرور الوقت؛ وهذا جانب أساسي يُمكن فيه لفهم المُجمِّعات وشفرة الآلة تحسين الأداء. يُعد نقل الشفرة غير المتأثر بالحلقات التكرارية وتحسين قيمة الإرجاع مثالين على التحسينات التي تُقلل الحاجة إلى متغيرات مساعدة، بل ويمكن أن تُؤدي إلى أداء أسرع من خلال تجنب التحسينات غير المباشرة.while(true)for(;;)while(true)truefor(;;)
مستوى البناء
بين مستوى الكود المصدري ومستوى الترجمة، يمكن استخدام التوجيهات وعلامات البناء لضبط خيارات الأداء في الكود المصدري والمترجم على التوالي، مثل استخدام تعريفات المعالج المسبق لتعطيل ميزات البرامج غير الضرورية، أو التحسين لنماذج معالجات أو قدرات أجهزة محددة، أو التنبؤ بالتفرع ، على سبيل المثال. تستفيد أنظمة توزيع البرامج القائمة على الكود المصدري، مثل Ports في BSD و Portage في Gentoo ، من هذا النوع من التحسين.
مستوى التجميع
يُسهم استخدام مُصرّف مُحسِّن مع تفعيل التحسينات في ضمان تحسين البرنامج القابل للتنفيذ على الأقل بالقدر الذي يُمكن للمُصرّف تحقيقه بشكل معقول. راجع قسم "المُصرّف المُحسِّن" لمزيد من التفاصيل.
مستوى التجميع
على أدنى مستوى، يُمكن لكتابة التعليمات البرمجية باستخدام لغة التجميع ، المصممة لمنصة أجهزة معينة، أن تُنتج تعليمات برمجية أكثر كفاءة واختصارًا إذا استغل المبرمج كامل نطاق تعليمات الآلة . ولهذا السبب، كُتبت العديد من أنظمة التشغيل المستخدمة في الأنظمة المدمجة تقليديًا بلغة التجميع. نادرًا ما تُكتب البرامج (باستثناء البرامج الصغيرة جدًا) من البداية إلى النهاية بلغة التجميع نظرًا للوقت والتكلفة اللازمين. تُترجم معظم البرامج من لغة برمجة عالية المستوى إلى لغة التجميع، ثم تُحسّن يدويًا. عندما تكون الكفاءة والحجم أقل أهمية، يُمكن كتابة أجزاء كبيرة بلغة برمجة عالية المستوى.
مع وجود المزيد من المترجمات المحسّنة الحديثة والتعقيد الأكبر لوحدات المعالجة المركزية الحديثة ، أصبح من الصعب كتابة كود أكثر كفاءة مما يولده المترجم، وقليل من المشاريع تحتاج إلى خطوة التحسين "النهائية" هذه.
يُصمَّم جزء كبير من البرامج المكتوبة اليوم ليعمل على أكبر عدد ممكن من الأجهزة. ونتيجةً لذلك، لا يستفيد المبرمجون والمترجمون دائمًا من التعليمات الأكثر كفاءة التي توفرها وحدات المعالجة المركزية الأحدث، أو من خصائص النماذج القديمة. إضافةً إلى ذلك، قد يظل كود التجميع المُحسَّن لمعالج معين دون استخدام هذه التعليمات غير مثالي على معالج آخر، مما يتطلب ضبطًا مختلفًا للكود.
في العادة اليوم، بدلاً من الكتابة بلغة التجميع، يستخدم المبرمجون برنامج تفكيك الشفرة لتحليل مخرجات المترجم وتغيير شفرة المصدر عالية المستوى بحيث يمكن تجميعها بكفاءة أكبر، أو فهم سبب عدم كفاءتها.
مدة التشغيل
تستطيع المترجمات الفورية إنتاج شفرة آلية مخصصة بناءً على بيانات وقت التشغيل، على حساب زيادة في تكلفة الترجمة. يعود تاريخ هذه التقنية إلى أوائل محركات التعبيرات النمطية ، وقد انتشرت على نطاق واسع مع Java HotSpot وV8 لـ JavaScript. في بعض الحالات، قد تتمكن تقنية التحسين التكيفي من إجراء تحسينات وقت التشغيل تتجاوز قدرة المترجمات الثابتة، وذلك عن طريق ضبط المعلمات ديناميكيًا وفقًا للمدخلات الفعلية أو عوامل أخرى.
التحسين الموجه بالملف الشخصي هو أسلوب تحسين تجميع مسبق (AOT) يعتمد على ملفات تعريف وقت التشغيل، وهو مشابه لنظير "الحالة المتوسطة" الثابتة للتقنية الديناميكية للتحسين التكيفي.
يمكن للتعليمات البرمجية ذاتية التعديل أن تغير نفسها استجابة لظروف وقت التشغيل من أجل تحسين التعليمات البرمجية؛ وكان هذا أكثر شيوعًا في برامج لغة التجميع.
تُتيح بعض تصميمات وحدات المعالجة المركزية إمكانية إجراء بعض التحسينات أثناء التشغيل. ومن الأمثلة على ذلك التنفيذ خارج الترتيب ، والتنفيذ التخميني ، وخطوط أنابيب التعليمات ، ومتنبئات التفرع . ويمكن للمترجمات أن تُساعد البرنامج على الاستفادة من هذه الميزات في وحدة المعالجة المركزية، على سبيل المثال من خلال جدولة التعليمات .
التحسينات المعتمدة على المنصة والتحسينات المستقلة عنها
يمكن تصنيف تحسين الكود بشكل عام إلى تقنيات تعتمد على المنصة وتقنيات مستقلة عنها. فبينما تُعدّ التقنيات المستقلة فعّالة على معظم المنصات أو جميعها، تستخدم التقنيات المعتمدة على المنصة خصائص محددة لمنصة واحدة، أو تعتمد على معايير خاصة بتلك المنصة أو حتى بالمعالج نفسه. ولذلك، قد يكون من الضروري كتابة أو إنتاج نسخ مختلفة من الكود نفسه لمعالجات مختلفة. على سبيل المثال، في حالة التحسين على مستوى الترجمة، تُعدّ التقنيات المستقلة عن المنصة تقنيات عامة (مثل فكّ الحلقات ، وتقليل استدعاءات الدوال، والروتينات الموفرة للذاكرة، وتقليل الشروط، إلخ)، والتي تؤثر على معظم بنى وحدات المعالجة المركزية بطريقة مماثلة. وقد ظهر مثال رائع على التحسين المستقل عن المنصة مع حلقة for الداخلية، حيث لوحظ أن الحلقة التي تحتوي على حلقة for داخلية تُجري عمليات حسابية أكثر في وحدة الزمن من حلقة بدونها أو حلقة تحتوي على حلقة while داخلية. [ 8 ] وبشكل عام، تهدف هذه التقنيات إلى تقليل طول مسار التعليمات الإجمالي المطلوب لإكمال البرنامج و/أو تقليل إجمالي استخدام الذاكرة أثناء العملية. من ناحية أخرى، تتضمن التقنيات المعتمدة على النظام الأساسي جدولة التعليمات، والتوازي على مستوى التعليمات ، والتوازي على مستوى البيانات ، وتقنيات تحسين ذاكرة التخزين المؤقت (أي المعلمات التي تختلف بين الأنظمة الأساسية المختلفة)، وقد تختلف جدولة التعليمات المثلى حتى على معالجات مختلفة من نفس البنية.
تقليل القوة
يمكن تنفيذ المهام الحسابية بعدة طرق مختلفة بكفاءة متفاوتة. يُعرف الإصدار الأكثر كفاءة ذو الوظائف المكافئة باسم " تقليل القوة" . على سبيل المثال، انظر إلى مقتطف كود C التالي الذي يهدف إلى حساب مجموع جميع الأعداد الصحيحة من 1 إلى N :
int sum = 0 ; for ( int i = 1 ; i <= N ; ++ i ) { sum += i ; } printf ( "sum: %d \n " , sum );يمكن إعادة كتابة هذا الكود (بافتراض عدم وجود تجاوز حسابي ) باستخدام صيغة رياضية مثل:
int sum = N * ( 1 + N ) / 2 ; printf ( "sum: %d \n " , sum );تتمثل عملية التحسين، التي تُنفذ أحيانًا تلقائيًا بواسطة مُترجم مُحسِّن، في اختيار طريقة ( خوارزمية ) أكثر كفاءة حسابية مع الحفاظ على نفس الوظائف. راجع كفاءة الخوارزميات لمناقشة بعض هذه التقنيات. مع ذلك، يُمكن غالبًا تحقيق تحسين ملحوظ في الأداء عن طريق إزالة الوظائف الزائدة.
لا تُعدّ عملية التحسين دائمًا عمليةً واضحةً أو بديهية. ففي المثال أعلاه، قد تكون النسخة "المحسّنة" أبطأ من النسخة الأصلية إذا كانت قيمة N صغيرةً بما يكفي، وكان الجهاز المستخدم أسرع بكثير في عمليات الجمع والتكرار مقارنةً بعمليات الضرب والقسمة.
المفاضلات
في بعض الحالات، يعتمد التحسين على استخدام خوارزميات أكثر تعقيدًا، والاستفادة من "حالات خاصة" و"حيل" خاصة، وإجراء مفاضلات معقدة. قد يكون البرنامج "المُحسَّن بالكامل" أكثر صعوبة في الفهم، وبالتالي قد يحتوي على أخطاء أكثر من النسخ غير المُحسَّنة. إضافةً إلى التخلص من الأنماط البرمجية السيئة الواضحة، فإن بعض التحسينات على مستوى الكود تُقلل من سهولة الصيانة.
يركز التحسين عادةً على تحسين جانب أو جانبين فقط من جوانب الأداء: وقت التنفيذ، استخدام الذاكرة، مساحة القرص، عرض النطاق الترددي، استهلاك الطاقة، أو أي مورد آخر. ويتطلب هذا عادةً موازنةً بين العوامل ، حيث يتم تحسين أحدها على حساب عوامل أخرى. على سبيل المثال، زيادة حجم ذاكرة التخزين المؤقت تُحسّن أداء وقت التشغيل، ولكنها تزيد أيضًا من استهلاك الذاكرة. ومن المفاضلات الشائعة الأخرى وضوح الكود وإيجازه.
في بعض الأحيان، يضطر المبرمج المسؤول عن تحسين البرنامج إلى اتخاذ قرار بتحسين أداء بعض العمليات على حساب تقليل كفاءة عمليات أخرى. وقد تكون هذه المفاضلات غير تقنية في بعض الأحيان ، كما في حالة نشر منافس لنتيجة قياسية يجب تجاوزها لتحقيق نجاح تجاري، ولكن قد يترتب على ذلك تقليل كفاءة الاستخدام العادي للبرنامج. ويُشار إلى هذه التغييرات أحيانًا، على سبيل المزاح، بـ" التشاؤم" .
الاختناقات
قد يشمل التحسين تحديد نقطة الاختناق في النظام ، أي المكون الذي يُحدّ من الأداء. وعلى مستوى الشيفرة البرمجية، غالباً ما تكون هذه النقطة هي " النقطة الساخنة "، أي جزء حرج من الشيفرة يستهلك الموارد المطلوبة بشكل أساسي ، مع العلم أنه قد يكون هناك عامل آخر، مثل زمن استجابة الإدخال/الإخراج أو عرض النطاق الترددي للشبكة.
في علوم الحاسوب، غالبًا ما يتبع استهلاك الموارد شكلًا من أشكال توزيع قانون القوة ، ويمكن تطبيق مبدأ باريتو على تحسين استخدام الموارد من خلال ملاحظة أن 80% من الموارد تُستخدم عادةً بواسطة 20% من العمليات. [ 9 ] في هندسة البرمجيات، غالبًا ما يكون من الأنسب تقدير أن 90% من وقت تنفيذ برنامج الحاسوب يُقضى في تنفيذ 10% من التعليمات البرمجية (وهو ما يُعرف بقانون 90/10 في هذا السياق).
تُحقق الخوارزميات وهياكل البيانات الأكثر تعقيدًا أداءً جيدًا مع كميات كبيرة من البيانات، بينما تُعدّ الخوارزميات البسيطة أكثر ملاءمةً لكميات البيانات الصغيرة. قد تفوق تكلفة الإعداد والتهيئة والعوامل الثابتة للخوارزمية الأكثر تعقيدًا فوائدها، وبالتالي قد تكون الخوارزمية الهجينة أو الخوارزمية التكيفية أسرع من أي خوارزمية منفردة. يُمكن استخدام مُحلل الأداء لتضييق نطاق القرارات بشأن الوظائف التي تُناسب كل حالة. [ 10 ]
لذا، لا يقتصر تحليل الأداء على كشف الاختناقات فحسب، بل يوفر أيضًا مجموعة متنوعة من أساليب توجيه التحسين. وتُعرف الخوارزميات التجريبية بأنها استخدام الأساليب التجريبية، وخاصة تحليل الأداء، لدراسة سلوك الخوارزميات، بهدف تمكين المطورين من فهمها، مما قد يُفضي إلى تحسينات مُخطط لها. أما التحسين الموجه بتحليل الأداء، فهو استخدام بيانات تحليل الأداء كمدخلات لمترجم أو مُفسر مُحسِّن. وترتبط بعض لغات البرمجة بأدوات مُخصصة لهذا النوع من التحسين. [ 11 ] وتركز بعض أساليب تحليل الأداء على التحسينات القائمة على استخدام الذاكرة المؤقتة . [ 12 ] وتشمل فوائد تحليل الأداء الأخرى تحسين إدارة الموارد وتعزيز تجربة المستخدم.
في بعض الحالات، قد يُساهم زيادة الذاكرة في تسريع عمل البرنامج. على سبيل المثال، عادةً ما يقرأ برنامج التصفية كل سطر ويُصفّيه ويُخرجه فورًا. هذا لا يستهلك سوى ذاكرة كافية لسطر واحد، لكن الأداء يكون ضعيفًا في الغالب بسبب زمن استجابة كل عملية قراءة من القرص. يُعدّ تخزين النتيجة مؤقتًا فعالًا بالمثل، وإن كان يتطلب أيضًا استخدامًا أكبر للذاكرة.
متى يجب التحسين
عادةً، تتضمن عملية التحسين اختيار أفضل الخوارزميات وهياكل البيانات بشكل عام. [ 13 ] في كثير من الأحيان، يمكن للتحسينات الخوارزمية أن تُحسّن الأداء بشكل كبير، على عكس التحسينات الجزئية التي نادرًا ما تُحسّن الأداء بأكثر من بضعة بالمئة. [ 14 ] إذا انتظرنا حتى نهاية دورة التطوير لإجراء التحسين، فقد يتطلب تغيير الخوارزمية إعادة كتابة شاملة.
في كثير من الأحيان، قد يؤدي التحسين الدقيق إلى تقليل سهولة قراءة البرامج أو الأنظمة وتعقيدها، مما قد يجعل صيانتها وتصحيح أخطائها أكثر صعوبة.
أدلى دونالد كنوث بالتصريحين التاليين حول التحسين:
"ينبغي أن ننسى الكفاءات الصغيرة، لنقل حوالي 97% من الوقت: فالتحسين المبكر هو أصل كل شر. ومع ذلك، لا ينبغي أن نفوت فرصنا في تلك النسبة الحاسمة البالغة 3%" [ 15 ]
(كما نسب الاقتباس إلى توني هوار بعد عدة سنوات، [ 16 ] على الرغم من أن هذا قد يكون خطأً حيث ينفي هوار أنه هو من صاغ العبارة. [ 17 ] )
"في التخصصات الهندسية الراسخة، لا يعتبر التحسن بنسبة 12٪، والذي يمكن تحقيقه بسهولة، هامشيًا أبدًا، وأعتقد أن وجهة النظر نفسها يجب أن تسود في هندسة البرمجيات" [ 15 ].
كثيراً ما يُستخدم مصطلح "التحسين المبكر" كذريعة ضد جميع أنواع التحسين في جميع الحالات ولجميع الأغراض. [ 18 ] [ 19 ] [ 20 ] [ 21 ] وغالباً ما يؤدي استخدام الكود النظيف إلى جعل الكود أكثر تعقيداً من الكود الأبسط والأكثر كفاءة. [ 22 ]
عند تحديد ما يجب تحسينه، ينبغي استخدام قانون أمدال لتحديد أولويات الأجزاء بناءً على الوقت الفعلي الذي يقضيه في جزء معين، وهو أمر ليس واضحًا دائمًا من خلال النظر إلى الكود دون تحليل الأداء .
عملياً، غالباً ما يكون من الضروري مراعاة أهداف الأداء عند تصميم البرمجيات في البداية، ومع ذلك، يتعين على المبرمجين الموازنة بين مختلف العوامل. فتكلفة التطوير مرتفعة، والأجهزة سريعة.
تتميز المترجمات الحديثة بكفاءة عالية لدرجة أن التحسينات المرجوة في الأداء قد لا تتحقق أحيانًا. ونظرًا لأن المترجمات تُجري العديد من التحسينات التلقائية، فقد ينتج عن بعض هذه التحسينات ملف تنفيذي مطابق للأصل. كما أن بعض مكونات الجهاز قد تُقلل من تأثير التحسينات الدقيقة. على سبيل المثال، قد يقوم الجهاز بتخزين البيانات مؤقتًا، بينما يتم تخزينها مؤقتًا على مستوى البرنامج.
وحدات الماكرو
تتخذ عملية تحسين الأداء أثناء تطوير التعليمات البرمجية باستخدام وحدات الماكرو أشكالاً مختلفة في لغات البرمجة المختلفة.
في بعض لغات البرمجة الإجرائية، مثل C و C++ ، تُنفَّذ وحدات الماكرو باستخدام استبدال الرموز. أما اليوم، فيمكن استخدام الدوال المضمنة كبديل آمن من حيث النوع في كثير من الحالات. في كلتا الحالتين، يمكن للمترجم إجراء تحسينات إضافية على جسم الدالة المضمنة أثناء الترجمة، بما في ذلك طي الثوابت ، مما قد ينقل بعض العمليات الحسابية إلى وقت الترجمة.
في العديد من لغات البرمجة الوظيفية ، تُنفَّذ وحدات الماكرو باستخدام استبدال أشجار التحليل/أشجار بناء الجملة المجردة أثناء عملية التحليل، مما يُزعم أنه يجعلها أكثر أمانًا للاستخدام. ونظرًا لاستخدام التفسير في كثير من الحالات، تُعد هذه إحدى طرق ضمان تنفيذ هذه العمليات الحسابية فقط أثناء التحليل، وأحيانًا تكون الطريقة الوحيدة.
ابتكرت لغة ليسب هذا النمط من وحدات الماكرو، وغالبًا ما تُسمى هذه الوحدات "وحدات ماكرو شبيهة بليسب". ويمكن تحقيق تأثير مماثل باستخدام البرمجة الوصفية للقوالب في لغة سي++ .
في كلتا الحالتين، يُنقل العمل إلى وقت الترجمة. يكمن الفرق بين وحدات الماكرو في لغة C من جهة، ووحدات الماكرو الشبيهة بلغة Lisp وبرمجة القوالب الوصفية في لغة C++ من جهة أخرى، في أن الأدوات الأخيرة تسمح بإجراء عمليات حسابية عشوائية في وقت الترجمة/التحليل، بينما لا يُجري توسيع وحدات الماكرو في لغة C أي عملية حسابية، ويعتمد على قدرة المُحسِّن على القيام بذلك. إضافةً إلى ذلك، لا تدعم وحدات الماكرو في لغة C الاستدعاء الذاتي أو التكرار بشكل مباشر ، لذا فهي ليست كاملة تورينج .
ومع ذلك، وكما هو الحال مع أي عملية تحسين، فإنه من الصعب في كثير من الأحيان التنبؤ بمكان تأثير هذه الأدوات قبل اكتمال المشروع.
التحسين الآلي واليدوي
انظر أيضًا: تصنيف: تحسينات المُصرّف
يمكن أتمتة عملية التحسين بواسطة المترجمات أو تنفيذها بواسطة المبرمجين. عادةً ما تكون المكاسب محدودة في التحسين المحلي، وأكبر في التحسين الشامل. في الغالب، يكون التحسين الأقوى هو إيجاد خوارزمية متفوقة .
عادةً ما يتولى المبرمجون تحسين النظام بأكمله نظرًا لتعقيده الشديد بالنسبة لخوارزميات التحسين الآلية. في هذه الحالة، يقوم المبرمجون أو مديرو النظام بتعديل الشيفرة البرمجية بشكل صريح لتحسين أداء النظام ككل. ورغم أن هذه الطريقة قد تُحسّن الكفاءة، إلا أنها أكثر تكلفة بكثير من التحسينات الآلية. ونظرًا لتأثير العديد من العوامل على أداء البرنامج، فإن نطاق تحسينه واسع. تُستخدم الخوارزميات الاستدلالية والتعلم الآلي لمعالجة تعقيد تحسين البرامج. [ 23 ]
استخدم أداة تحليل الأداء (أو أداة تحليل الأداء ) لتحديد أجزاء البرنامج التي تستهلك أكبر قدر من الموارد - أي نقطة الاختناق . يعتقد المبرمجون أحيانًا أن لديهم فكرة واضحة عن مكان نقطة الاختناق، لكن الحدس غالبًا ما يكون خاطئًا. تحسين جزء غير مهم من التعليمات البرمجية لن يُحسّن الأداء العام بشكل ملحوظ.
عندما يكون الاختناق موضعيًا، تبدأ عملية التحسين عادةً بإعادة النظر في الخوارزمية المستخدمة في البرنامج. في أغلب الأحيان، يمكن تصميم خوارزمية معينة خصيصًا لمشكلة محددة، مما يُحقق أداءً أفضل من الخوارزمية العامة. على سبيل المثال، تُنجز مهمة فرز قائمة ضخمة من العناصر عادةً باستخدام خوارزمية الفرز السريع ، وهي إحدى أكثر الخوارزميات العامة كفاءة. ولكن إذا كانت هناك خاصية معينة للعناصر قابلة للاستغلال (على سبيل المثال، إذا كانت مرتبة بالفعل بترتيب معين)، فيمكن استخدام طريقة مختلفة، أو حتى خوارزمية فرز مُخصصة.
بعد أن يتأكد المبرمج إلى حد معقول من اختيار أفضل خوارزمية، يمكن البدء بتحسين الكود. يمكن فكّ الحلقات (لتقليل الحمل الزائد للحلقات، مع العلم أن هذا قد يؤدي غالبًا إلى انخفاض السرعة إذا أدى إلى إثقال ذاكرة التخزين المؤقت للمعالج )، ويمكن استخدام أنواع بيانات أصغر ما يمكن، ويمكن استخدام العمليات الحسابية الصحيحة بدلًا من العمليات الحسابية العشرية، وما إلى ذلك. (راجع مقال كفاءة الخوارزميات للاطلاع على هذه التقنيات وغيرها).
قد تعود اختناقات الأداء إلى قيود اللغة البرمجية وليس إلى الخوارزميات أو هياكل البيانات المستخدمة في البرنامج. أحيانًا، يمكن إعادة كتابة جزء أساسي من البرنامج بلغة برمجة مختلفة تتيح وصولًا مباشرًا أكثر إلى الجهاز. على سبيل المثال، من الشائع في لغات البرمجة عالية المستوى مثل بايثون أن تحتوي على وحدات مكتوبة بلغة C لزيادة السرعة. يمكن للبرامج المكتوبة بلغة C أن تحتوي على وحدات مكتوبة بلغة التجميع . يمكن للبرامج المكتوبة بلغة D استخدام المُجمِّع المضمن .
إعادة كتابة أجزاء من البرنامج تُؤتي ثمارها في هذه الظروف، وذلك بفضل قاعدة عامة تُعرف بقانون 90/10، والتي تنص على أن 90% من الوقت يُقضى في 10% من الكود، و10% فقط من الوقت يُقضى في الـ 90% المتبقية من الكود. لذا، فإن بذل جهد فكري في تحسين جزء صغير من البرنامج يُمكن أن يُحدث فرقًا كبيرًا في السرعة الإجمالية ، إذا أمكن تحديد الجزء (الأجزاء) الصحيح.
قد يؤدي التحسين اليدوي أحيانًا إلى تقليل سهولة قراءة الكود. لذا، ينبغي توثيق تحسينات الكود بعناية (ويُفضل استخدام التعليقات المضمنة)، وتقييم تأثيرها على التطوير المستقبلي.
يُطلق على البرنامج الذي يُجري عملية التحسين التلقائي اسم المُحسِّن . تُدمج معظم المُحسِّنات في المُترجمات وتعمل أثناء عملية الترجمة. ويمكن للمُحسِّنات في كثير من الأحيان تخصيص الكود المُولَّد ليتناسب مع معالجات مُحدَّدة.
تقتصر التحسينات الآلية اليوم بشكل شبه حصري على تحسينات المُصرّف . ومع ذلك، ولأن تحسينات المُصرّف عادةً ما تقتصر على مجموعة ثابتة من التحسينات العامة، فهناك طلب كبير على مُحسِّنات تقبل وصفًا للمشكلة وتحسينات خاصة بلغة البرمجة، مما يسمح للمهندس بتحديد تحسينات مُخصصة. تُسمى الأدوات التي تقبل وصفًا للتحسينات بأنظمة تحويل البرامج ، وقد بدأت تُستخدم في أنظمة برمجية حقيقية مثل لغة C++.
تقوم بعض لغات البرمجة عالية المستوى ( مثل Eiffel و Esterel ) بتحسين برامجها باستخدام لغة وسيطة .
تهدف الحوسبة الشبكية أو الحوسبة الموزعة إلى تحسين النظام بأكمله، عن طريق نقل المهام من أجهزة الكمبيوتر ذات الاستخدام العالي إلى أجهزة الكمبيوتر ذات وقت الخمول.
الوقت المستغرق للتحسين
في بعض الأحيان، قد يمثل الوقت المستغرق لإجراء التحسين في حد ذاته مشكلة.
لا يُضيف تحسين الكود الحالي عادةً ميزات جديدة، بل قد يُضيف أخطاءً جديدة إلى الكود الذي كان يعمل سابقًا (كما هو الحال مع أي تغيير). ولأن الكود المُحسَّن يدويًا قد يكون أقل وضوحًا من الكود غير المُحسَّن، فقد يؤثر التحسين على سهولة صيانته. للتحسين تكلفة، ومن المهم التأكد من جدوى هذا الاستثمار.
قد يحتاج مُحسِّن الأداء التلقائي (أو مُجمِّع التحسين ، وهو برنامج يُجري تحسينًا للتعليمات البرمجية) إلى التحسين نفسه، إما لزيادة كفاءة البرامج المستهدفة أو لتسريع عملية التجميع. عادةً ما تستغرق عملية التجميع مع تفعيل التحسين وقتًا أطول، ولكن هذه المشكلة لا تظهر عادةً إلا في البرامج الكبيرة جدًا.
على وجه الخصوص، بالنسبة للمترجمات في الوقت المناسب، فإن أداء مكون الترجمة في وقت التشغيل ، الذي يتم تنفيذه جنبًا إلى جنب مع التعليمات البرمجية المستهدفة، هو المفتاح لتحسين سرعة التنفيذ الإجمالية.
تحسين زائف
أحيانًا، قد تؤثر "التحسينات" سلبًا على الأداء. فالتزامن والتوازي يُسببان تكلفة أداء إضافية كبيرة، وربما زيادة في استهلاك الطاقة. تجدر الإشارة إلى أن لغة C نادرًا ما تستخدم المعالجة المتعددة الصريحة، ومع ذلك فهي تعمل عادةً أسرع من أي لغة برمجة أخرى. غالبًا ما يؤدي التخزين المؤقت على القرص، والتقسيم إلى صفحات، والتبديل إلى زيادات كبيرة في استهلاك الطاقة وتآكل الأجهزة. كما أن تشغيل العمليات في الخلفية لتحسين وقت بدء التشغيل يُبطئ جميع العمليات الأخرى.
انظر أيضاً
- المعيار – تقييم الأداء المعياري
- ذاكرة التخزين المؤقت (الحوسبة) - مساحة تخزين إضافية تتيح الوصول بشكل أسرع إلى وحدة التخزين الرئيسية
- الخوارزميات التجريبية – استخدام الأساليب التجريبية لدراسة الخوارزميات
- مُجمِّع مُحسِّن – مُجمِّع يُحسِّن الكود المُولَّد
- هندسة الأداء – تشمل التقنيات المطبقة خلال دورة حياة تطوير الأنظمة
- توقعات الأداء
- تحسين الأداء
- التحسين الموجه بالملف التعريفي – تقنية تحسين المُترجم
- تطوير البرمجيات – إنشاء وصيانة البرمجيات
- اختبار أداء البرمجيات – اختبار الأداء في ظل عبء عمل محدد
- تحليل الشفرة الثابتة – تحليل برامج الحاسوب دون تنفيذها. صفحات تعرض أوصافًا مختصرة لأهداف إعادة التوجيه.
مراجع
- ↑ روبرت سيدجويك ، الخوارزميات ، 1984، ص 84.
- ↑ أنطونيو، أندرياس؛ لو، وو-شنغ (2021). التحسين العملي (ملف PDF) . نصوص في علوم الحاسوب ( الطبعة الثانية). سبرينغر . ص 1. doi : 10.1007/978-1-0716-0843-2 . ISBN 978-1-0716-0841-8.
- ↑ "التحسين الفائق: توليد كود مثالي قابل للإثبات باستخدام برمجة مجموعة الإجابات" . جامعة باث . تم الاسترجاع في 11 سبتمبر 2024 .
- ↑ "تحسين الأداء في تطوير البرمجيات: تسريع تطبيقاتك" . تم الاطلاع عليه بتاريخ 12 يوليو 2025 .
- ↑ أغراوال، أميت. "تعظيم الكفاءة: تطبيق نظام مراقبة الأداء" . تم الاطلاع عليه بتاريخ 12 يوليو 2025 .
- ↑ دوبي، إنجو. "دليل المسافر إلى أداء جافا: الماضي والحاضر والمستقبل" . تم الاطلاع عليه بتاريخ 12 يوليو 2025 .
- ↑ مولينز، كريج س. "تأثير التغيير على هياكل قواعد البيانات" . تم الاطلاع عليه بتاريخ 12 يوليو 2025 .
- ↑ أدومي، توسين ب. (2018-08-01). "بنية البرنامج الحلقي الداخلي: طريقة أسرع لتنفيذ البرنامج" . علوم الحاسوب المفتوحة . 8 (1): 115-122 . doi : 10.1515/comp-2018-0004 .
- ↑ ويسكوت، بوب (2013). كتاب أداء كل حاسوب، الفصل 3: قوانين مفيدة . كريت سبيس . ISBN 978-1482657753.
- ↑ كراوس، كيرك ج. "تحليل الأداء مع التركيز" . تم الاطلاع عليه بتاريخ 15 أغسطس 2017 .
- ↑ "التحسين الموجه بالملف الشخصي" . تم الاطلاع عليه بتاريخ 12 يوليو 2025 .
- ↑ مطورو Valgrind (2006). "5.2.2". دليل مستخدم Valgrind . شركة Network Theory المحدودة.
- ↑ "مغالطة التحسين المبكر" .
- ↑ "مغالطة التحسين المبكر" .
- 1 2 كنوت، دونالد (ديسمبر 1974). "البرمجة المهيكلة باستخدام عبارات الانتقال". مجلة ACM Computing Surveys . 6 (4): 268. CiteSeerX 10.1.1.103.6084 . doi : 10.1145/356635.356640 . S2CID 207630080 .
- ↑ أخطاء TeX ، في البرمجيات - الممارسة والخبرة ، المجلد 19، العدد 7 (يوليو 1989)، الصفحات 607-685، أعيد طبعه في كتابه البرمجة الأدبية (ص 276).
- ↑ "التحسين المبكر أصل كل شر" . hans.gerwitz.com . تم الاطلاع عليه بتاريخ 18 ديسمبر 2020.
مع ذلك، لم يدّعِ هوار ذلك عندما سألته في يناير 2004
. - ↑ "مغالطة التحسين المبكر" .
- ↑ "ليست كل عمليات التحسين سابقة لأوانها" .
- ↑ "متى لا يكون التحسين المبكر مناسبًا" .
- ↑ ""تجنب التحسين المبكر" لا يعني "كتابة كود غير ضروري"." .
- ↑ "التجريدات المبكرة" .
- ↑ ميميتي، سويجب؛ بلانا، صبري؛ بينوتو، أليسيو؛ كولودزيج، جوانا؛ برانديتش، إيفونا (26 أبريل 2018). "استخدام الخوارزميات الاستكشافية والتعلم الآلي لتحسين برمجيات أنظمة الحوسبة المتوازية: مراجعة منهجية للأدبيات". الحوسبة . 101 (8). سبرينغر فيينا: 893-936 . arXiv : 1801.09444 . Bibcode : 2018arXiv180109444M . doi : 10.1007/s00607-018-0614-9 . S2CID 13868111 .
للمزيد من القراءة
- جون بنتلي : كتابة برامج فعالة ، رقم ISBN 0-13-970251-2.
- دونالد كنوث : فن برمجة الحاسوب
- كيفية كتابة كود عددي سريع: مقدمة موجزة
- كتاب "ما يجب أن يعرفه كل مبرمج عن الذاكرة" بقلم أولريش دريبر - يشرح بنية أنظمة الذاكرة الفرعية الحديثة ويقترح كيفية استخدامها بكفاءة
- "تحليل وتحسين أداء المعالجات متعددة النوى في نظام لينكس باختصار" ، شرائح عرض تقديمي من إعداد فيليب موتشي
- تحسين البرمجة بقلم بول هسيه
- كتابة برامج فعّالة ("قواعد بنتلي") بقلم جون بنتلي
- "أنماط الأداء المضادة" بقلم بارت سمولدرز
- تحسين البرمجيات
- مواضيع لغات البرمجة
- تحسين الحاسوب
