محمدرضا گلابوند
محمدرضا گلابوند
خواندن ۴ دقیقه·۶ ماه پیش

پرفورمنس بهتر در #C


توی این مطلب سعی کردم از زوایای مختلف به روش‌های افزایش سرعت برنامه در C# بپردازم.

قسمت‌هایی که برای افزایش سرعت بررسی می‌کنم شامل: کار با string ها، Design Pattern های مرتبط، خوندن داده از دیتابیس و نکات مفید هستند.

کار با string

تغییر یک string: در واقع رشته‌ها غیر قابل تغییر یا immutable هستند و وقتی برای جمع کردن متغیرهای رشته از عملگر + استفاده می‌کنید، در پشت صحنه یک فضای جدید در حافظه انتخاب می‌شه و مقدار جدید در اونجا قرار می‌گیره و مقدار قبلی توسط GC حذف می‌شه. اما با استفاده از StringBuilder تغییرات در فضای فعلی انجام می‌شه و فضای جدیدی ایجاد نمی‌شه.

مقایسه دو متغیر string: برای این کار بسته به موقعیت، روش‌های مختلفی لازمه. در زیر موقعیت‌های مختلف با بهترین روش رو نوشتم.

  • دو متغیر string با مقادیر کوتاه: برای این مقایسه بهترین روش استفاده از متد Equals هست.
shortStringVar1.Equals(shortStringVar2);
  • یک متغیر string با مقدار بلند و یک متغیر string با مقدار کوتاه: برای این مقایسه بهترین روش همون روش معمول استفاده از عملگر == هست.
longStringVar == shortStringVar;
  • مقایسه دو متغیر string برای بررسی کردن نام کاربری یا ایمیل که بزرگی یا کوچکی حروف انگلیسی استفاده شده مهم نیستند: برای این مقایسه بهترین روش استفاده از متد Compare هست.
string.Compare(stringVar1, stringVar2, ignoreCase: true);


استفاده از Design Pattern مرتبط

در اصل الگوهای طراحی برای توسعه نرم افزار ها به صورت منعطف در برابر تغییر(flexible)، تعمیر پذیر(maintainable) و قابلیت استفاده دوباره(reusable) ایجاد شدند. اما برخی از الگو های طراحی علاوه بر این ویژگی ها از نظر سرعت هم به برنامه کمک می‌کنند که من اونهارو در زیر به صورت فهرست و با توضیحی خلاصه نوشتم.

  • الگوی Flyweight: هدف اصلی این الگو اشتراک گذاری ویژگی های اصلی بین اشیاء مشابه و کاهش تعداد اشیاء موجود در برنامه است.
  • الگوی Signleton: این الگو اطمینان حاصل می‌کنه که یک کلاس فقط یک نمونه و یک نقطه دسترسی عمومی داشته باشه. این الگو به کاهش استفاده از حافظه کمک می‌کنه.
  • الگوی Prototype: این امکان رو میده که برای هربار استفاده، بجای ساخت یک نمونه جدید از یک شئ، ازش یک کپی بسازیم و از کپی اون استفاده کنیم. این کار باعث صرفه جویی در زمان و حافظه استفاده شده می‌شه.
  • الگوی Builder: این الگو باعث می‌شه تا اشیاء پیچیده رو به صورت گام به گام و با استفاده از اشیاء ساده‌تر ایجاد کنیم. این کار باعث خواناتر و ساختارمندتر شدن کد و در نتیجه افزایش سرعت برنامه می‌شه.

البته که این توضیحات کوتاه برای یادگیری این الگو‌ها کافی نیست. اگه علاقه‌مند به یادگیری بیشتر درمورد الگوهای طراحی هستید پیشنهاد من کتاب #Design Patterns in C نوشته شده توسط Vaskaran Sarcar و یا دوره C# Design Patterns توسط Kevin Dockx در سایت Pluralsight هست.


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

در استفاده از LINQ تا جایی که ممکنه شرط‌های مورد نیاز رو قبل از متد‌هایی که نتیجه کوئری رو برمی‌گردونند(مثل ()First. و ()ToList. و ()Count. و ...) استفاده کنید. با اینکار شرط‌ها در دیتابیس اجرا و فقط داده‌هایی که شرط‌های مورد نیاز رو دارند از دیتابیس فراخونده می‌شن و نه تمام داده‌ها. درصورت نیاز می‌تونید شرط‌های دیگه‌ای بعد از این قرار بدید.

از کتاب C# 10 in a Nutshell اگه این عملیات با فرض وجود دیتابیس انجام بشه، قسمت بالا(Subquery) روی سرور دیتابیس و  قسمت پایین(Outer query) روی حافظه انجام میشه.
از کتاب C# 10 in a Nutshell اگه این عملیات با فرض وجود دیتابیس انجام بشه، قسمت بالا(Subquery) روی سرور دیتابیس و قسمت پایین(Outer query) روی حافظه انجام میشه.



در دیتابیس ستون داده‌هایی که روی اونها زیاد عملیات جستجو انجام می‌دید INDEX کنید.

اگه از EFCore استفاده می‌کنید دو راه برای ایندکس کردن وجود داره استفاده از Data Annotation و یا Fluent API

برای مثال اگه می‌خواید از بین نام کاربری‌ها زیاد جستجو انجام بدید می‌تونید از روش‌های زیر استفاده کنید.

  • استفاده از Data Annotation

بالای پراپرتی مورد نظر از [Index] استفاده کنید.

[Index(IsUnique = true)] public string Username { get; set; }


  • استفاده از Fluent API

از متد HasIndex استفاده کنید.

modelBuilder.Entity<User>().HasIndex(u => u.Username).IsUnique();


نکات مفید

  • سرعت حلقه‌های for و foreach زیاد متفاوت نیست و انتخاب بین این دو از نظر سرعت اهمیتی نداره.
  • استفاده از "record class" و "class" سرعت یکسانی ارائه می‌کنند. "record" در عملکرد برنامه تغییر ایجاد نمی‌کنه و فقط کد نویسی رو اسون‌تر می‌کنه.
  • در مورد "record struct" و "struct" هم همینطور.
  • نوع داده‌های عددی int، byte و long تقریبا سرعت یکسانی ارائه می‌دن. اما decimal سنگینه و فقط باید برای محاسبات تجاری و قیمت‌ها استفاده بشه.

MrGolabvand.ir




الگوهای طراحیdesign patternsسی شارپperformanceasp net core
توسعه دهنده .NET
شاید از این پست‌ها خوشتان بیاید