بهینه‌سازی برنامه

در علم کامپیوتر، بهینه‌سازی برنامه یا بهینه‌سازی نرم‌افزار، روند اصلاح یک سیستم نرم‌افزاری است تا بعضی از جنبه‌های آن را کارآمدتر کند یا از منابع کمتر استفاده کند. به‌طور کلی، یک برنامه کامپیوتری ممکن است بهینه شود تا سریعتر اجرا شود یا بتوان آن را با ذخیره حافظه کمتر یا با استفاده از منابع دیگر یا حتی قدرت کمتری خلق کرد

عمومی

اگر چه کلمه "بهینه سازی" ریشه در "بهینه"دارد، فرایند بهینه‌سازی برای تولید یک سیستم به‌طور مطلوب نادر است. سیستم بهینه تنها در یک برنامه یا برای یک مخاطب مطلوب است. ممکن است مقدار زمانی که یک برنامه برای انجام برخی کارها طی می‌کند یا حافظه بیشتری که مصرف می‌کند را کاهش دهد. در یک برنامه کاربردی که فضای حافظه در اصل کم است، ممکن است به صورت عمدی یک الگوریتم کندتر را برای استفاده از حافظه کمتر انتخاب شود. اغلب طراحی "یک اندازه که به همه اختصاص داده می‌شود " وجود دارد که در همه موارد به خوبی کار می‌کند، بنابراین مهندسان به منظور بهینه‌سازی ویژگی‌هایی که بیشترین توجه را به خود جلب می‌کنند، در کنار هم قرار می‌گیرند.. علاوه بر این تلاش لازم برای ساختن یک قطعه نرم‌افزاری به‌طور کامل بهینه است - حتی درصورت ناتوانی برای هر گونه پیشرفت در ان - تقریباً همیشه بیش از معقول بودن برای مزایایی است که شامل می‌شود؛ بنابراین فرایند بهینه‌سازی ممکن است قبل از رسیدن به یک راه حل کاملاً مطلوب متوقف شود. خوشبختانه، اغلب موارد این است که بیشترین پیشرفت در اوایل روند انجام می‌شود.

بهینه‌سازی بستر وابسته و مستقل

بهینه‌سازی کد را می‌توان همچنین به‌طور گسترده به عنوان طبقه‌بندی پلت فرم‌های وابسته و تکنیک‌های مستقل از پلتفرم دانست. در حالی که آن‌هایی که در اکثر یا تمام سیستم عامل‌ها مؤثر هستند، تکنیک‌های وابسته به پلت فرم از ویژگی‌های خاص یک پلت فرم استفاده می‌کنند یا به پارامترهای بسته به پلت فرم تک یا حتی بر روی پردازنده تک تک تکیه می‌کنند؛ بنابراین ممکن است نوشتن یا تولید نسخه‌های مختلف از همان کد برای پردازنده‌های مختلف مورد نیاز باشد. به عنوان مثال، در مورد بهینه‌سازی سطح کامپایل، تکنیک‌های مستقل از پلت فرم، تکنیک‌های عمومی هستند (مانند حلقه، کاهش تماس‌های عملکردی، رویه‌های کارآمد حافظه، کاهش شرایط و غیره)، که اکثر معماری‌های CPU را در یک مسیر مشابه را شامل می‌شود یک نمونه عالی از بهینه‌سازی مستقل از پلت فرم با حلقه درونی نشان داده شده‌است، جایی که یک حلقه با یک حلقه درونی مشاهده شد، محاسبات بیشتری را در هر واحد زمان انجام می‌دهد تا یک حلقه بدون آن یا یک حلقه داخلی در حالی که حلقه است به حساب آورد. به‌طور کلی، این‌ها به منظور کاهش کل مسیر آموزش مورد نیاز برای تکمیل برنامه یا کاهش کل استفاده از حافظه در طول فرایند خدمت می‌کنند. از سوی دیگر، تکنیک‌های وابسته به پلت فرم شامل برنامه‌ریزی دستورالعمل، هماهنگی در سطح دروس، سطح هماهنگی داده‌ها، تکنیک‌های بهینه‌سازی حافظه پنهان (یعنی پارامترهای متفاوت در سیستم عامل‌های مختلف) و برنامه‌ریزی دستورالعمل مطلوب حتی در پردازنده‌های مختلف همان معماری ممکن است.

کاهش قدرت

وظایف محاسباتی را می‌توان با روش‌های مختلف با کارایی متفاوت انجام داد. یک نسخه کارآمد با قابلیت معادل به عنوان یک کاهش قدرت شناخته شده‌است. برای مثال، کد قطعه زیر C را در نظر بگیرید که قصد دارد مجموع اعداد صحیح را از ۱ به N بدست آورد: 
int i, sum = 0;for (i = 1; i <= N; ++i) {
  sum += i;}printf("sum: %d\n", sum);
 این کد (با فرض وجود سرریز حسی) می‌تواند با استفاده از یک فرمول ریاضی مانند: 
int sum = N * (1 + N) / 2;printf("sum: %d\n", sum);
 بهینه‌سازی، گاهی اوقات توسط یک کامپایلر بهینه‌سازی انجام می‌شود، این است که یک روش (الگوریتم) را انتخاب کنید که کارایی بیشتری در محاسبات است، در حالی که حفظ همان کارکرد. هم مهم است برای رفع برخی از این تکنیک‌ها، کارایی الگوریتمی را مشاهده می‌کنید. با این حال، بهبود قابل توجهی در عملکرد اغلب می‌تواند با حذف قابلیت‌های بیرونی به دست آید.
بهینه‌سازی همیشه یک فرایند واضح یا بصری نیست. در مثال بالا، نسخه بهینه شده ممکن است در مقایسه با نسخه اصلی کندتر از نسخه اصلی باشد اگر N به اندازه کافی کوچک باشد و سخت‌افزار خاص در انجام عملیات علاوه بر اضافه کردن و حلقه بیش از ضرب و تقسیم، بسیار سریعتر اتفاق می‌افتد.

Trade-offs

در برخی موارد، با این حال، بهینه‌سازی مبتنی بر استفاده از الگوریتم‌های پیچیده‌تر یا استفاده از «موارد خاص» و «حقه‌های ویژه» و انجام پیچیده تجارت است. برنامه به‌طور کامل بهینه شده ممکن است دشوار باشد و از این رو ممکن است خطاهای بیشتری را نسبت به نسخه‌های غیرمتعارف داشته باشد. بعلاوه، حذف برخی از مشکلات واضح، برخی از بهینه‌سازی‌های سطح کد باعث کاهش قابلیت نگهداری می‌شود.
بهینه‌سازی به‌طور کلی بر بهبود تنها یک یا دو جنبه از عملکرد تمرکز می‌کند: زمان اجرا، استفاده از حافظه، فضای دیسک، پهنای باند، مصرف برق یا برخی از منابع دیگر. این معمولاً نیاز به یک trade-offدارد؛ که در آن یک عامل به هزینه دیگران بهینه‌سازی شده‌است. به عنوان مثال، افزایش حجم حافظه پنهان باعث بهبود عملکرد در زمان اجرا می‌شود، اما مصرف حافظه نیز افزایش می‌یابد. سایر موارد رایج شامل وضوح و مختصر کد است.
مواردی وجود دارد که برنامه‌نویس بهینه سا باید تصمیم بگیرد که نرم‌افزار را برای برخی عملیات بهتر کند، اما هزینه عملیات دیگر کمتر کارآمد است. این ترکیبات ممکن است گاهی غیر فنی باشد مانند زمانی که یک رقیب نتیجه یک معیار را منتشر کرده‌است که باید به منظور بهبود موفقیت تجاری مورد ضرب و شتم قرار گیرد، اما احتمالاً با استفاده از نرمال بودن نرم‌افزار کمتر کارآمد می‌شود. چنین تغییراتی گاهی اوقات به شوخی به عنوان pessimizations اشاره شده‌است.

تنگنا

بهینه‌سازی ممکن است شامل یافتن یک تنگنا در یک سیستم باشد - یک جزء که عامل محدودکننده در عملکرد است. از لحاظ کد، این اغلب یک نقطه داغ است - قسمت بحرانی کد که مصرف‌کننده اولیه منابع مورد نیاز است - هرچند که این می‌تواند عامل دیگری مانند زمان تأخیر I / O یا پهنای باند شبکه باشد.
در علم کامپیوتر، مصرف منابع اغلب به نوعی توزیع قانون قدرت پیوسته‌است و اصل پارتو را می‌توان به بهینه‌سازی منابع با توجه به اینکه ۸۰٪ از منابع معمولاً با استفاده از ۲۰٪ از عملیات مورد استفاده قرار می‌گیرد. در مهندسی نرم‌افزار اغلب یک تقریب بهتر است که ۹۰٪ زمان اجرای برنامه کامپیوتری صرف ۱۰٪ از کد انجام می‌شود (قانون ۹۰/۱۰ در این زمینه شناخته می‌شود).
الگوریتم پیچیده‌تر و ساختار داده‌ها با بسیاری از اقلام خوب عمل می‌کند، در حالی که الگوریتم‌های ساده برای مقادیر کوچک داده‌ها مناسب تر هستند - زمان راه اندازی، زمان شروع و عوامل ثابت الگوریتم پیچیده‌تر می‌تواند مزیت را بیش از حد و در نتیجه الگوریتم ترکیبی یا سازگار الگوریتم ممکن است سریعتر از هر الگوریتم تک باشد. یک پروفیل عملکرد می‌تواند مورد استفاده قرار گیرد تا محدودیت تصمیم‌های مربوط به عملکرد که مطابق با شرایط است.
در برخی موارد، اضافه کردن حافظه بیشتر می‌تواند کمک کند که برنامه را سریعتر اجرا کند. به عنوان مثال، یک برنامه فیلتر معمولاً هر خط را مطالعه می‌کند و فوراً آن خط را خروجی می‌کند. این تنها با استفاده از حافظه کافی برای یک خط استفاده می‌کند، اما عملکرد به‌طور معمول ضعیف است، به دلیل تأخیر هر خواندن دیسک. با خواندن کل فایل و سپس نوشتن نتیجه فیلتر شده، می‌توان عملکرد را بسیار بهبود داد، هرچند که از حافظه بسیار بیشتری استفاده می‌کند. ذخیره‌سازی نتایج مشابه نیز مؤثر است، هرچند که نیاز به استفاده از حافظه بزرگتر نیز دارد.

ماکروها

بهینه‌سازی در طول توسعه کد با استفاده از ماکرو در فرم‌های مختلف در زبان‌های مختلف صورت می‌گیرد.
در بعضی از زبان‌های رویه ای، مانند C و C ++، ماکروها با استفاده از جایگزینی نشانه اجرا می‌شوند. امروزه، توابع درون خطی می‌تواند به عنوان یک جایگزین امن در بسیاری موارد استفاده شود. در هر دو حالت، بدن تابع مجهز می‌تواند به وسیله کامپایلر بهینه‌سازی کامپایل زمان بیشتری را انجام دهد، از جمله تأخیر ثابت، که ممکن است برخی از محاسبات را برای زمان کامپایل حرکت کند.
در بسیاری از زبان‌های برنامه‌نویسی کاربردی، ماکروها با استفاده از پارسا زمان جایگزینی درختان تجزیه‌کننده / درخت‌های انتزاعی نحو اجرا می‌شوند که ادعا می‌کند آن‌ها را برای استفاده ایمن تر می‌کند. از آنجایی که در بسیاری از موارد از تفسیر استفاده می‌شود، این یکی از راه‌های اطمینان از این است که چنین محاسباتی تنها در زمان تجزیه انجام می‌شود و گاهی اوقات تنها راه است.
Lisp این سبک از ماکرو را ایجاد کرد  و چنین ماکروهای اغلب به نام "ماکرو مانند Lisp" نامیده می‌شود. یک اثر مشابه را می‌توان با استفاده از metaprogramming قالب در C ++ بدست آورد.
در هر دو مورد، کار به زمان کامپایل منتقل شده‌است. تفاوت بین C ماکروها در یک طرف، و Lisp مانند ماکروها و C ++ برنامه‌نویسی خودآرا در طرف دیگر، آن است که ابزارهای دوم اجازه می‌دهد انجام محاسبات دلخواه در زمان کامپایل / تجزیه زمان، در حالی که گسترش C ماکروها هیچ انجام نمی‌محاسبات، و بر توانایی بهینه‌ساز برای انجام آن متکی است. علاوه بر این، ماکرو C مستقیماً از بازگشت یا تکرار پشتیبانی نمی‌کند، بنابراین تورینگ کامل نیست.
با این حال، همان‌طور که با هر بهینه‌سازی، اغلب پیش‌بینی می‌شود که این ابزار تا زمانی که پروژه کامل شود، بیشترین تأثیر را دارد، مشکل است.

بهینه‌سازی خودکار و دستی

بهینه‌سازی می‌تواند توسط کامپایلرها یا توسط برنامه نویسان انجام شود. دستاوردها معمولاً برای بهینه‌سازی محلی محدود می‌شوند و برای بهینه‌سازی جهانی بزرگتر است. به‌طور معمول، قوی‌ترین بهینه‌سازی، یافتن یک الگوریتم برتر الگوریتم است.
بهینه‌سازی یک سیستم کلی معمولاً توسط برنامه نویسان انجام می‌شود، زیرا برای بهینه سازان خودکار بسیار پیچیده‌است. در این وضعیت، برنامه نویسان یا مدیران سیستم به صراحت کد را تغییر می‌دهند تا سیستم کلی بهتر عمل کند. اگر چه می‌تواند کارایی بهتر را تولید کند، اما به مراتب گرانتر از بهینه‌سازی خودکار است. از آنجایی که پارامترهای بسیاری بر عملکرد برنامه تأثیر می‌گذارند، فضای بهینه‌سازی برنامه بزرگ است. فراشناخت و یادگیری ماشین برای رفع پیچیدگی بهینه‌سازی برنامه استفاده می‌شود.
از بخش پروفایل (یا آنالیز کننده عملکرد) برای پیدا کردن بخش‌هایی از برنامه استفاده می‌کنید که بیشترین منابع را می‌گیرند - تنگنا گاهی اوقات برنامه‌نویسان معتقدند که ایده ای روشن از جایی که تنگنا است، اما شهود اغلب اشتباه است.  بهینه‌سازی قطعه ای غیر مهم از کد به‌طور معمول برای انجام کار کلی کمک نمی‌کند.
هنگامی که تنگنا محلی سازی می‌شود، بهینه‌سازی معمولاً با بازخوانی الگوریتم مورد استفاده در برنامه آغاز می‌شود. اغلب اوقات الگوریتم خاصی می‌تواند به‌طور خاص برای یک مشکل خاص طراحی شده و کارایی بهتر از یک الگوریتم ژنریک را فراهم کند. برای مثال، کار مرتب‌سازی لیست عظیمی از اقلام معمولاً با یک روش مرتب‌سازی سریع انجام می‌شود که یکی از کارآمدترین الگوریتم‌های عمومی است. اما اگر برخی از ویژگی‌های مورد استفاده قابل بهره‌برداری باشد (به عنوان مثال، آن‌ها قبلاً در یک نظم خاص مرتب شده‌اند)، روش دیگری می‌تواند مورد استفاده قرار گیرد یا حتی یک مرتب‌سازی مرتب‌سازی سفارشی.
پس از اینکه برنامه‌نویس متوجه شد که بهترین الگوریتم انتخاب شده‌است، بهینه‌سازی کد می‌تواند شروع شود. حلقه‌ها می‌توانند به صورت غیرمجاز (برای سربار حلقه پایین‌تر، اگر چه اغلب می‌تواند به سرعت پایین‌تر در صورتی که بیش از حد حافظه نهان سی‌پی‌یو)، نوع داده‌ها به عنوان کوچک ممکن است می‌تواند استفاده شود، ریاضی عدد صحیح می‌تواند به جای نقطه شناور استفاده شود، و غیره. (نگاه کنید به مقاله کارایی الگوریتمی برای این و سایر تکنیک‌ها)
تنگناهای عملکرد می‌تواند به دلیل محدودیت‌های زبان به جای الگوریتم‌ها یا ساختارهای داده مورد استفاده در برنامه باشد. گاهی اوقات یک بخش مهم از برنامه را می‌توان دوباره در یک زبان برنامه‌نویسی متفاوت نوشت که دسترسی مستقیم به دستگاه پایه را فراهم می‌کند. برای مثال، برای زبان‌های بسیار سطح مانند Python معمول است که ماژول‌هایی که در C نوشته شده‌اند برای سرعت بیشتر باشد. برنامه‌هایی که قبلاً در C نوشته شده‌اند می‌توانند ماژول‌هایی را که در مجمع نوشته شده‌اند داشته باشند. برنامه‌های نوشته شده در دی می‌توانند از مونتاژ خطی استفاده کنند.
بخش‌های بازنویسی "پرداخت می‌شود" در این شرایط به دلیل یک قاعده کلی "شناخته شده به عنوان قانون ۹۰/۱۰، که می‌گوید ۹۰ درصد از زمان در ۱۰٪ از کد صرف، و تنها ۱۰٪ از زمان در ۹۰٪ باقی مانده از کد؛ بنابراین، تلاش فکری برای بهینه‌سازی فقط بخش کوچکی از برنامه می‌تواند تأثیر بزرگی بر سرعت کلی داشته باشد - اگر قسمت درست(ها) قابل نصب باشد.
بهینه‌سازی دستی گاهی اوقات عواقبی ناشی از خواندن را مختل می‌کند؛ بنابراین بهینه‌سازی کد باید با دقت مستندسازی شود (ترجیحا با استفاده از نظرات درون خطی)، و تأثیر آنها بر پیشرفت آینده مورد ارزیابی قرار می‌گیرد.
برنامه ای که بهینه‌سازی خودکار را انجام می‌دهد بهینه‌سازی شده‌است. اکثر بهینه‌سازها در کامپایلرها جاسازی شده و در طول تدوین کار می‌کنند. بهینه سازان اغلب می‌توانند کد تولید شده را به پردازنده‌های خاصی متصل کنند.
امروزه بهینه‌سازی خودکار تقریباً به‌طور انحصاری به بهینه‌سازی کامپایلر محدود می شود. با این حال، به دلیل اینکه بهینه‌سازی کامپایلر معمولاً به یک مجموعه ثابت و بهینه‌سازی به‌طور کلی محدود می‌شود، تقاضای قابل توجهی برای بهینه سازان وجود دارد که می‌توانند توصیف‌های مربوط به بهینه‌سازی‌های مربوط به مشکل و زبان را بپذیرند و به مهندس اجازه می‌دهد تا بهینه‌سازی‌های سفارشی را مشخص کنند. ابزارهایی که توصیف‌های بهینه‌سازی را می‌پذیرند، سیستم‌های تبدیل سیستم نامیده می‌شوند و شروع به استفاده از سیستم‌های واقعی نرم‌افزار مانند C ++ می‌شوند.
برخی از زبان‌های سطح بالا (ایفل، استرل) برنامه‌های خود را با استفاده از زبان متوسط بهینه‌سازی می‌کنند.
محاسبات گرید یا محاسبات توزیع شده به منظور بهینه‌سازی کل سیستم، با حرکت دادن وظایف از رایانه‌های با استفاده بالا به رایانه‌ها با زمان بیکاری است.

زمان برای بهینه‌سازی

گاهی اوقات، زمان انجام شده برای انجام بهینه‌سازی در خود ممکن است یک مسئله باشد.
بهینه‌سازی کد موجود معمولاً ویژگی‌های جدیدی را اضافه نمی‌کند و بدتر از آن ممکن است اشکالات جدیدی در کد قبلی ایجاد شده باشد (همان‌طور که هر تغییر ممکن است). از آنجا که ممکن است کد بهینه‌سازی شده به صورت دستی ممکن است «قابل خواندن» کمتر از کد غیرقطعی باشد، بهینه‌سازی ممکن است باعث حفظ قابلیت نگهداری آن شود. بهینه‌سازی می‌آید در قیمت و مهم است که مطمئن شوید که سرمایه‌گذاری ارزشمند است.
بهینه‌سازی خودکار (یا کامپایلر بهینه‌سازی، برنامه ای که بهینه‌سازی کد را انجام می‌دهد) خود باید بهینه‌سازی شده باشد، یا به منظور بهبود کارایی برنامه‌های هدف خود یا افزایش سرعت عملیات خود. یک کامپایل انجام شده با بهینه‌سازی «روشن» معمولاً طول می‌کشد طول می‌کشد، اگر چه این معمولاً تنها مشکل زمانی که برنامه‌ها بسیار بزرگ است.
به‌طور خاص، برای کامپایلرهای فقط در زمان، اجزای اجزای کامپایل زمان اجرای اجرا، همراه با کد هدف خود، کلید بهبود سرعت اجرای کلی است.