مقدمة: لماذا أداء لغة C# مهم
في عالم تطوير البرمجيات الحديث، تؤثر سرعة التطبيق بشكل مباشر على تجربة المستخدم وتكاليف البنية التحتية والقدرة التنافسية للمنتج. توفر منصة .NET ولغة C# أدوات قوية لإنشاء أنظمة عالية الأداء، ومع ذلك، يمكن أن يؤدي الاستخدام غير الصحيح للميزات (على سبيل المثال، إدارة الذاكرة غير المنضبطة أو الخوارزميات غير الفعالة) إلى تأخيرات خطيرة واستهلاك مفرط للموارد. في هذه المقالة، سنقوم بتفصيل التقنيات الرئيسية لتحسين أداء تطبيقات C# التي ستساعدك على كتابة كود أسرع وأكثر كفاءة.
1. التنميط: ابحث عن الاختناق قبل التحسين
قبل إجراء التغييرات، من الضروري تحديد المكان الذي يتم فيه قضاء معظم الوقت بدقة. بدون التنميط، فإنك تخاطر بتحسين ما هو سريع بالفعل، مع تفويت الاختناقات الحقيقية.
أدوات التنميط
- أدوات التشخيص في Visual Studio — أداة تنميط مدمجة لتحليل وحدة المعالجة المركزية والذاكرة والاستثناءات.
- dotMemory — أداة قوية لتحليل إدارة الذاكرة واكتشاف التسريبات.
- PerfView — أداة مجانية من Microsoft لتحليل أداء .NET العميق.
- BenchmarkDotNet — مكتبة لقياس الأداء الدقيق لأجزاء الكود الفردية.
مثال على استخدام BenchmarkDotNet لقياس سرعة طريقتين:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
public class StringBenchmark
{
private string[] data = Enumerable.Range(0, 1000).Select(i => $"Item {i}").ToArray();
[Benchmark]
public string ConcatenateWithPlus()
{
string result = "";
foreach (var s in data) result += s;
return result;
}
[Benchmark]
public string ConcatenateWithStringBuilder()
{
var sb = new System.Text.StringBuilder();
foreach (var s in data) sb.Append(s);
return sb.ToString();
}
}
// Run: BenchmarkRunner.Run<StringBenchmark>();
ستظهر نتائج الاختبار بوضوح أن StringBuilder أسرع بعشرات المرات من الربط باستخدام + في الحلقات.
2. إدارة الذاكرة وتقليل ضغط GC
جامع البيانات المهملة (GC) هو آلية قوية، لكن تشغيله المتكرر يمكن أن يؤثر سلبًا على الأداء، خاصة في الأنظمة عالية التحميل. الهدف الرئيسي هو تقليل عدد التخصيصات وعمر الكائنات.
2.1. استخدام الهياكل بدلاً من الفئات
إذا كان الكائن صغيرًا (أقل من 16-24 بايت) وله عمر قصير، ففكر في استخدام struct. يتم تخزين الهياكل على المكدس (أو مضمنة في الكائن الأصلي) ولا تخلق ضغطًا على GC.
// Class — heap allocation
public class PointClass
{
public int X { get; set; }
public int Y { get; set; }
}
// Struct — on the stack
public struct PointStruct
{
public int X;
public int Y;
}
2.2. تجميع الكائنات (Object Pooling)
للكائنات التي يتم إنشاؤها وتدميرها بشكل متكرر (مثل اتصالات قاعدة البيانات، المخازن المؤقتة)، استخدم مصفوفة. .NET Core يحتوي على تطبيق مدمج ObjectPool<T>.
using Microsoft.Extensions.ObjectPool;
var pool = new DefaultObjectPool<List<int>>(new ListPolicy());
var list = pool.Get();
try
{
// Work with the list
}
finally
{
pool.Return(list); // Return to the pool
}
2.3. Span<T> و Memory<T>
تسمح هذه الأنواع بالعمل مع مناطق الذاكرة المتجاورة دون تخصيصات إضافية. إنها مثالية للتحليل والعمل مع المصفوفات والسلاسل.
public int SumDigits(ReadOnlySpan<