تحليل أداء كود C#: إيجاد نقاط الاختناق للمبتدئين
\n\nيواجه كل مطور C# عاجلاً أم آجلاً موقفاً يكون فيه التطبيق بطيئاً. بدلاً من التخمين حول مكان المشكلة، يجب استخدام تحليل الأداء (profiling) - وهي عملية قياس أداء الكود لتحديد نقاط الاختناق. في هذه المقالة، سنشرح كيف يمكن لمطور C# مبتدئ أن يجد بسرعة ويحل مشاكل الأداء في مشاريع .NET.
\n\nما هو تحليل الأداء ولماذا هو مهم؟
\n\nتحليل الأداء (profiling) هو تحليل ديناميكي للبرنامج يوضح مقدار الوقت الذي يستغرقه تنفيذ كل دالة، وعدد مرات استدعائها، وكمية الذاكرة التي تستهلكها. على عكس تشغيل الكود البسيط، يعطي تحليل الأداء أرقاماً دقيقة وليس تخمينات.
\n\nالمقاييس الرئيسية لتحليل الأداء:
\n- \n
- CPU time — الوقت الذي يستغرقه المعالج لتنفيذ الكود. \n
- Allocations — عدد وحجم الذاكرة المخصصة. \n
- GC pressure — الحمل على جامع القمامة. \n
- I/O operations — وقت قراءة/كتابة البيانات. \n
بدون تحليل الأداء، غالباً ما يقوم المطورون "بتحسين" أجزاء خاطئة من الكود، مما يضيع ساعات على تحسينات دقيقة لا تؤثر على الأداء العام. قاعدة باريتو تعمل هنا بشكل مثالي: 20% من الكود تسبب 80% من البطء. مهمة تحليل الأداء هي إيجاد هذه الـ 20%.
\n\nأدوات تحليل أداء C# (.NET)
\n\nتتوفر عدة أدوات قوية لـ .NET. دعنا نستعرض ثلاثة أدوات رئيسية مناسبة للمبتدئين:
\n\n1. محلل الأداء المدمج في Visual Studio
\nيحتوي Visual Studio (الإصدار Community مجاني) على مجموعة أدوات تشخيص مدمجة. لتشغيل تحليل الأداء، اضغط Alt + F2 أو اختر Debug → Performance Profiler. يمكنك اختيار نوع التحليل: استخدام وحدة المعالجة المركزية (CPU Usage)، استخدام الذاكرة (Memory Usage)، أو تتبع تخصيص كائنات .NET (.NET Object Allocation Tracking).
// مثال على كود للاختبار\npublic class SlowCalculator\n{\n public double Compute(int iterations)\n {\n double result = 0;\n for (int i = 0; i < iterations; i++)\n {\n result += Math.Sqrt(i) * Math.Log(i + 1);\n }\n return result;\n }\n}\n\nبعد تشغيل المحلل، سترى الدوال "الساخنة" (hot path) مرتبة حسب وقت التنفيذ. يعرض Visual Studio أيضاً شجرة الاستدعاءات (call tree) - مما يساعد على فهم أي دالة تسبب المشاكل.
\n\n2. BenchmarkDotNet
\nهذه مكتبة لقياس أداء الدوال الفردية بدقة. تقوم تلقائياً بتشغيل الكود عدة مرات، وتسخين مترجم JIT، وتستبعد القيم الشاذة. قم بتثبيتها عبر NuGet: dotnet add package BenchmarkDotNet.
using BenchmarkDotNet.Attributes;\nusing BenchmarkDotNet.Running;\n\npublic class StringBenchmark\n{\n private const int N = 10000;\n private string _data = new string('x', N);\n\n [Benchmark]\n public string UseStringBuilder()\n {\n var sb = new System.Text.StringBuilder();\n for (int i = 0; i < 100; i++)\n sb.Append(_data);\n return sb.ToString();\n }\n\n [Benchmark]\n public string UseStringConcatenation()\n {\n string result = "";\n for (int i = 0; i < 100; i++)\n result += _data;\n return result;\n }\n}\n\n// التشغيل في Main:\n// var summary = BenchmarkRunner.Run<StringBenchmark>();\n\nسيصدر BenchmarkDotNet جدولاً بوقت التنفيذ، واستهلاك الذاكرة، والتخصيصات. سترى فوراً أن دمج السلاسل النصية في حلقة هو نقطة اختناق (O(n²) من حيث الذاكرة).
\n\n3. dotMemory / PerfView
\nلتحليل تسرب الذاكرة، استخدم dotMemory (مدفوع، مع نسخة تجريبية) أو PerfView المجاني من Microsoft. يظهران الكائنات التي لا يتم تحريرها بواسطة جامع القمامة وأين