کنترل سرعت برنامه
در صحبت های قبل به سرعت برنامه ها و نقش برنامه نویس در آن اشاره کردیم و گفتیم یکی از مهم ترین عوامل در بهسازی سرعت برنامه، کاهش دستورات تکرار شونده است.
درون رایانه هر کاری که قرار است انجام شود نیاز به زمان دارد. یک دستور if ساده حتی اگر شرط آن برقرار نباشد و کنترل برنامه به داخل بلاک if وارد نشود باز هم اگر این کار به تعداد زیاد انجام شود زمان گیر خواهد بود. حال می خواهیم ببینیم چه عوامل و نکات دیگری در سرعت برنامه موثر خواهد بود. الگوریتم مناسب شاید بتوان گفت مهم ترین و تاثیرگذارترین مساله در تعیین کارایی و سرعت یک برنامه، الگوریتم یا روش مورد استفاده در آن برنامه است. از ابتدای به وجود آمدن رایانه، برنامه نویسان و متخصصان درصدد طراحی الگوریتمی بوده اند که بتواند با صرف کمترین زمان، هزینه و انرژی آنها را به هدف برساند. ممکن است شخصی الگوریتمی طراحی کند که عمل بخصوصی را در مدت زمان مشخصی انجام دهد و شخص دیگری روشی ارائه دهد که بتواند همان کار را در زمان کمتری انجام دهد. مسلما برنامه ای با ارزش تر است که بتواند کاری را در کمترین زمان ممکن انجام دهد. به عنوان یک نمونه ساده فرض کنید برنامه ای قرار است یک سری داده را از ورودی به طور تصادفی دریافت کرده و آنها را مرتب کرده و به خروجی تحویل دهد. تاکنون روش های زیادی برای این کار مطرح شده است که هر یک به طریقی عمل مرتب سازی را انجام می دهد. هر کدام از آنها نیز نسبت به دیگری معایب و مزایایی دارد که آن روش را نسبت به بقیه متفاوت می سازد. یک برنامه نویس با توجه به نیازهای خود و شرایط موجود باید سعی کند بهترین روش را انتخاب کند و در صورتی که هیچ یک از روش های موجود پاسخگوی نیاز وی نبود خود اقدام به طراحی الگوریتمی کند که بتواند به نیازها پاسخ دهد. همیشه یک الگوریتم نامناسب تنها موجب کندی اجرا نخواهد شد. گاهی اگر یک الگوریتم زمان معقولی برای پاسخ دهی نداشته باشد، استفاده از آن عملا غیرممکن خواهد بود. به عنوان یک مثال ساده، مساله ای به نام فروشنده دوره گرد (tsp) در علوم رایانه مطرح است که حل آن به روش معمول در مواردی ممکن است به هزار سال زمان نیاز داشته باشد! این بدان معنی است که این روش عملا قابل اجرا نیست. همین مساله با همان ابعاد با یک روش دیگر می تواند در 5 دقیقه حل شود. ضمن این که روش جدید نیز که می تواند آن مساله را 5 دقیقه ای حل کند اگر ابعاد مساله را بزرگ تر کنیم آن هم ممکن است برای پاسخ دهی به سال ها زمان نیاز داشته باشد. بنابر این جدا از سرعت رایانه، به کارگیری یک الگوریتم مناسب در سرعت اجرای برنامه ها تاثیر مستقیم خواهد داشت. استفاده مناسب از حافظه اصلی و فایل همان طور که می دانید سرعت عمل حافظه اصلی در مقایسه با حافظه جانبی بسیار بیشتر است. اما ظرفیت حافظه اصلی محدود بوده و قیمت آن نیز نسبت به دیسک سخت گران تر است. در نوشتن برنامه ها، برنامه نویس باید به این مساله توجه کافی داشته باشد که برنامه نوشته شده باید حتی الامکان میزان کمتری حافظه اصلی را اشغال کند. یکی از معیارهای مهم در سنجش یک برنامه در کنار سرعت اجرای آن، میزان حافظه مصرفی آن است. اما استفاده صحیح و مناسب از آن باعث بهبود کارایی و افزایش سرعت برنامه خواهد شد. داده هایی که مقیم حافظه شده اند و روال ها و توابع برنامه به طور مستقیم از حافظه اصلی به آنها دسترسی دارند با حداکثر سرعت پردازش خواهند شد. بنابراین اگر قرار است روی داده هایی که قرار است کار زیادی با آنها داریم و درون فایل قرار دارند پردازشی کنیم، در صورتی که حجم آنها زیاد نیست بهتر است که فضایی را در حافظه اصلی برای آنها در نظر گرفته و آنها را به طریقی در آنجا مقیم کنیم و پس از اتمام پردازش روی آ نها، نتیجه را در فایل بازنویسی کنیم. البته اغلب امکان پردازش مستقیم داده ها از روی فایل نیز وجود دارد که در صورت استفاده از این امکان حجم کمتری از حافظه اصلی اشغال خواهد شد. اما عملیات ورودی™خروجی (i/o) یعنی خواندن و نوشتن مکرر از/ روی فایل زمان زیادی را از برنامه خواهد گرفت و ممکن است کارایی آن را بشدت کاهش دهد. هیچ قانونی برای استفاده از حافظه اصلی به جای فایل یا بالعکس برای برنامه نویسان وجود ندارد که بخواهند طبق آن عمل کنند. هر برنامه نویس با توجه به دانش و تجربه نسبی که دارد باید مناسب ترین روش را برای بهبود بازده برنامه خود اتخاذ کند. افزایش کارایی در ورودی/خروجی مسلم است که اگر برنامه با حافظه اصلی کار می کند بیشترین سرعت ممکن را خواهد داشت. اما زمانی که تصمیم براین شد که پردازش داده ها به طور مستقیم از روی فایل انجام شود، در به کارگیری آن روش نیز باید توجه لازم صورت گیرد. فرض کنید یک فایل حجیم صد مگابایتی داریم که قرار است روی تک تک بایت های آن پردازشی صورت گیرد و مجددا در فایل نوشته شود. مسلما مقیم کردن صدمگابایت داده در حافظه منطقی نخواهد بود و روش پردازش فایل انتخاب خواهد شد. حال اولین چیزی که به نظر می رسد آن است که داده ها را بایت به بایت از فایل خوانده و پس از پردازش مجددا به فایل برگردانیم. تجربه نشان داده است که این کار، حتی اگر تنها خواندن و نوشتن باشد و هیچ پردازش زمان گیری روی داده انجام نشود، باز هم کارایی و سرعت عمل برنامه بشدت کم خواهد بود. عملیات ورودی– خروجی نسبت به کارهای داخل cpu و حافظه اصلی از جمله کارهای زمان گیر به حساب می آید. حال اگر این کار با فایلی با حجم گفته شده بخواهد به تعداد بایت های فایل انجام گیرد، افت شدید کارایی برنامه چیز عجیبی نخواهد بود. بنابر این بهتر است با هر بار عملیات ورودی / خروجی و پس از مراجعه به دیسک، حجم بیشتری از فایل را فراخوانی کنیم و پس از مقیم کردن آن مقدار در حافظه، باقی کار را با سرعت حافظه اصلی انجام دهیم. حال این سوال مطرح می شود که پس از هربار مراجعه به دیسک چه مقدار از داده را به حافظه منتقل کنیم. ممکن است برای اجرای یک برنامه آنقدر حافظه اصلی دراختیار داشته باشیم که برنامه نویس تصمیم بگیرد پس از هر مراجعه به دیسک مثلا یک مگابایت از داده ها را به حافظه منتقل کند. این کار دو اشکال می تواند داشته باشد. اول این که این برنامه نظر میزان از حافظه مصرفی، بهینه نخواهد بود و اگر قرار باشد برنامه در رایانه ای با حافظه کمتر اجرا شود، امکان مواجه شدن با کمبود حافظه و افت کارایی در آن وجود خواهد داشت. از طرف دیگر اگر نرم افزار ما یک برنامه محاوره ای باشد، کاربر در هنگام خوانده شدن هر یک مگابایت باید مدتی صبر کند تا بتواند با سایر بخش های برنامه کار کند که این مساله نیز یک ضعف برای نرم افزار به شمار می رود. شاید بهترین حالت این باشد که پس از هر بار مراجعه به دیسک به میزان یک سکتور یا یک بلاک دیسک داده فراخوانی شود. یک بلاک دیسک معمولا 4 یا 16 کیلوبایت است که البته کار برهنگام فرمت کردن دیسک می تواند این مقدار را تعیین کند. اما به طور عام این مقدار در نظر گرفته می شود. فراخوانی یک بلاک داده در هر بار عملیات i/o چند مزیت دارد. یکی آن که کمترین میزان حافظه برای بالا بردن کارایی برنامه مصرف می شود. از این مقدارکمتر حجم عملیات i/o اضافه می شود و از این بیشتر ممکن است بدون افزایش محسوس کارایی تنها حافظه بیشتری مصرف شود. مزیت دیگر آن است که هنگام فراخوانی یک بلاک از دیسک، تضمین می شود که هر دیسک وقتی به محل مورد نظر رسید برای خواندن مقدار مورد نظر دیگر لازم نیست حرکت کند. چون یک بلاک داده در دیسک به صورت پشت سر هم نوشته می شود. با توجه به این که زمان گیرترین عمل در یک دیسک سخت، حرکت هد آن است، کارایی بهینه خواهد بود و البته باز هم نسبت به شرایط و محیط اجرا می توان تدابیر دیگری اندیشید که این برعهده طراح نرم افزار و مخصوصا برنامه نویس خواهد بود.
منبع: www.jamejamonline.com
/س
درون رایانه هر کاری که قرار است انجام شود نیاز به زمان دارد. یک دستور if ساده حتی اگر شرط آن برقرار نباشد و کنترل برنامه به داخل بلاک if وارد نشود باز هم اگر این کار به تعداد زیاد انجام شود زمان گیر خواهد بود. حال می خواهیم ببینیم چه عوامل و نکات دیگری در سرعت برنامه موثر خواهد بود. الگوریتم مناسب شاید بتوان گفت مهم ترین و تاثیرگذارترین مساله در تعیین کارایی و سرعت یک برنامه، الگوریتم یا روش مورد استفاده در آن برنامه است. از ابتدای به وجود آمدن رایانه، برنامه نویسان و متخصصان درصدد طراحی الگوریتمی بوده اند که بتواند با صرف کمترین زمان، هزینه و انرژی آنها را به هدف برساند. ممکن است شخصی الگوریتمی طراحی کند که عمل بخصوصی را در مدت زمان مشخصی انجام دهد و شخص دیگری روشی ارائه دهد که بتواند همان کار را در زمان کمتری انجام دهد. مسلما برنامه ای با ارزش تر است که بتواند کاری را در کمترین زمان ممکن انجام دهد. به عنوان یک نمونه ساده فرض کنید برنامه ای قرار است یک سری داده را از ورودی به طور تصادفی دریافت کرده و آنها را مرتب کرده و به خروجی تحویل دهد. تاکنون روش های زیادی برای این کار مطرح شده است که هر یک به طریقی عمل مرتب سازی را انجام می دهد. هر کدام از آنها نیز نسبت به دیگری معایب و مزایایی دارد که آن روش را نسبت به بقیه متفاوت می سازد. یک برنامه نویس با توجه به نیازهای خود و شرایط موجود باید سعی کند بهترین روش را انتخاب کند و در صورتی که هیچ یک از روش های موجود پاسخگوی نیاز وی نبود خود اقدام به طراحی الگوریتمی کند که بتواند به نیازها پاسخ دهد. همیشه یک الگوریتم نامناسب تنها موجب کندی اجرا نخواهد شد. گاهی اگر یک الگوریتم زمان معقولی برای پاسخ دهی نداشته باشد، استفاده از آن عملا غیرممکن خواهد بود. به عنوان یک مثال ساده، مساله ای به نام فروشنده دوره گرد (tsp) در علوم رایانه مطرح است که حل آن به روش معمول در مواردی ممکن است به هزار سال زمان نیاز داشته باشد! این بدان معنی است که این روش عملا قابل اجرا نیست. همین مساله با همان ابعاد با یک روش دیگر می تواند در 5 دقیقه حل شود. ضمن این که روش جدید نیز که می تواند آن مساله را 5 دقیقه ای حل کند اگر ابعاد مساله را بزرگ تر کنیم آن هم ممکن است برای پاسخ دهی به سال ها زمان نیاز داشته باشد. بنابر این جدا از سرعت رایانه، به کارگیری یک الگوریتم مناسب در سرعت اجرای برنامه ها تاثیر مستقیم خواهد داشت. استفاده مناسب از حافظه اصلی و فایل همان طور که می دانید سرعت عمل حافظه اصلی در مقایسه با حافظه جانبی بسیار بیشتر است. اما ظرفیت حافظه اصلی محدود بوده و قیمت آن نیز نسبت به دیسک سخت گران تر است. در نوشتن برنامه ها، برنامه نویس باید به این مساله توجه کافی داشته باشد که برنامه نوشته شده باید حتی الامکان میزان کمتری حافظه اصلی را اشغال کند. یکی از معیارهای مهم در سنجش یک برنامه در کنار سرعت اجرای آن، میزان حافظه مصرفی آن است. اما استفاده صحیح و مناسب از آن باعث بهبود کارایی و افزایش سرعت برنامه خواهد شد. داده هایی که مقیم حافظه شده اند و روال ها و توابع برنامه به طور مستقیم از حافظه اصلی به آنها دسترسی دارند با حداکثر سرعت پردازش خواهند شد. بنابراین اگر قرار است روی داده هایی که قرار است کار زیادی با آنها داریم و درون فایل قرار دارند پردازشی کنیم، در صورتی که حجم آنها زیاد نیست بهتر است که فضایی را در حافظه اصلی برای آنها در نظر گرفته و آنها را به طریقی در آنجا مقیم کنیم و پس از اتمام پردازش روی آ نها، نتیجه را در فایل بازنویسی کنیم. البته اغلب امکان پردازش مستقیم داده ها از روی فایل نیز وجود دارد که در صورت استفاده از این امکان حجم کمتری از حافظه اصلی اشغال خواهد شد. اما عملیات ورودی™خروجی (i/o) یعنی خواندن و نوشتن مکرر از/ روی فایل زمان زیادی را از برنامه خواهد گرفت و ممکن است کارایی آن را بشدت کاهش دهد. هیچ قانونی برای استفاده از حافظه اصلی به جای فایل یا بالعکس برای برنامه نویسان وجود ندارد که بخواهند طبق آن عمل کنند. هر برنامه نویس با توجه به دانش و تجربه نسبی که دارد باید مناسب ترین روش را برای بهبود بازده برنامه خود اتخاذ کند. افزایش کارایی در ورودی/خروجی مسلم است که اگر برنامه با حافظه اصلی کار می کند بیشترین سرعت ممکن را خواهد داشت. اما زمانی که تصمیم براین شد که پردازش داده ها به طور مستقیم از روی فایل انجام شود، در به کارگیری آن روش نیز باید توجه لازم صورت گیرد. فرض کنید یک فایل حجیم صد مگابایتی داریم که قرار است روی تک تک بایت های آن پردازشی صورت گیرد و مجددا در فایل نوشته شود. مسلما مقیم کردن صدمگابایت داده در حافظه منطقی نخواهد بود و روش پردازش فایل انتخاب خواهد شد. حال اولین چیزی که به نظر می رسد آن است که داده ها را بایت به بایت از فایل خوانده و پس از پردازش مجددا به فایل برگردانیم. تجربه نشان داده است که این کار، حتی اگر تنها خواندن و نوشتن باشد و هیچ پردازش زمان گیری روی داده انجام نشود، باز هم کارایی و سرعت عمل برنامه بشدت کم خواهد بود. عملیات ورودی– خروجی نسبت به کارهای داخل cpu و حافظه اصلی از جمله کارهای زمان گیر به حساب می آید. حال اگر این کار با فایلی با حجم گفته شده بخواهد به تعداد بایت های فایل انجام گیرد، افت شدید کارایی برنامه چیز عجیبی نخواهد بود. بنابر این بهتر است با هر بار عملیات ورودی / خروجی و پس از مراجعه به دیسک، حجم بیشتری از فایل را فراخوانی کنیم و پس از مقیم کردن آن مقدار در حافظه، باقی کار را با سرعت حافظه اصلی انجام دهیم. حال این سوال مطرح می شود که پس از هربار مراجعه به دیسک چه مقدار از داده را به حافظه منتقل کنیم. ممکن است برای اجرای یک برنامه آنقدر حافظه اصلی دراختیار داشته باشیم که برنامه نویس تصمیم بگیرد پس از هر مراجعه به دیسک مثلا یک مگابایت از داده ها را به حافظه منتقل کند. این کار دو اشکال می تواند داشته باشد. اول این که این برنامه نظر میزان از حافظه مصرفی، بهینه نخواهد بود و اگر قرار باشد برنامه در رایانه ای با حافظه کمتر اجرا شود، امکان مواجه شدن با کمبود حافظه و افت کارایی در آن وجود خواهد داشت. از طرف دیگر اگر نرم افزار ما یک برنامه محاوره ای باشد، کاربر در هنگام خوانده شدن هر یک مگابایت باید مدتی صبر کند تا بتواند با سایر بخش های برنامه کار کند که این مساله نیز یک ضعف برای نرم افزار به شمار می رود. شاید بهترین حالت این باشد که پس از هر بار مراجعه به دیسک به میزان یک سکتور یا یک بلاک دیسک داده فراخوانی شود. یک بلاک دیسک معمولا 4 یا 16 کیلوبایت است که البته کار برهنگام فرمت کردن دیسک می تواند این مقدار را تعیین کند. اما به طور عام این مقدار در نظر گرفته می شود. فراخوانی یک بلاک داده در هر بار عملیات i/o چند مزیت دارد. یکی آن که کمترین میزان حافظه برای بالا بردن کارایی برنامه مصرف می شود. از این مقدارکمتر حجم عملیات i/o اضافه می شود و از این بیشتر ممکن است بدون افزایش محسوس کارایی تنها حافظه بیشتری مصرف شود. مزیت دیگر آن است که هنگام فراخوانی یک بلاک از دیسک، تضمین می شود که هر دیسک وقتی به محل مورد نظر رسید برای خواندن مقدار مورد نظر دیگر لازم نیست حرکت کند. چون یک بلاک داده در دیسک به صورت پشت سر هم نوشته می شود. با توجه به این که زمان گیرترین عمل در یک دیسک سخت، حرکت هد آن است، کارایی بهینه خواهد بود و البته باز هم نسبت به شرایط و محیط اجرا می توان تدابیر دیگری اندیشید که این برعهده طراح نرم افزار و مخصوصا برنامه نویس خواهد بود.
منبع: www.jamejamonline.com
/س