
Loading ..
Please wait while we prepare...
3/20/2025
عند فحص أداء التعليمات البرمجية بشكل صحيح، يساعد ذلك في اتخاذ قرارات أفضل بشأن كيفية كتابة البرنامج، وما إذا كان يعمل بسرعة أم توجد طرق أفضل لكتابة التعليمات البرمجية. وفي حال وجود نسختين من نفس التعليمات البرمجية، يمكن تحديد أي منهما أسرع وأيهما يستهلك موارد أقل.
يساعد هذا النوع من التحليل في تحديد مدى ثبات ودقة نتائج الاختبارات.
📌 قد توجد بعض الاختلافات الطبيعية في الأداء بسبب عوامل مثل بيئة التشغيل أو الأجهزة المستخدمة.
المتوسط (Mean): يعني متوسط الوقت الذي استغرقته العمليات المختلفة.
المتوسط = (مجموع قيم كل اختبار) / (عدد الاختبارات)
الانحراف المعياري (Standard Deviation): مقياس يوضح مدى تباعد النتائج عن المتوسط.
الحد الأدنى (Min): أقل وقت تم قياسه في الاختبارات.
الحد الأقصى (Max): أعلى وقت تم قياسه في الاختبارات.
الوسيط (Median): هو القيمة التي تتوسط نتائج الاختبارات بعد ترتيبها من الأدنى إلى الأعلى. قد يكون أدق من المتوسط عند وجود قيم متطرفة.
تحليل ثبات الأداء: يوفر التحليل الإحصائي فكرة عن مدى ثبات النتائج بين مجموعة الاختبارات. يمكن أن يكشف ما إذا كان هناك تباين في الأداء بسبب عوامل مختلفة مثل ضغط النظام أو طريقة استخدام الذاكرة.
كشف القيم المتطرفة (Outliers): قد تظهر قيم غير طبيعية بسبب حالات معينة مثل مشاكل في الأجهزة أو أخطاء في التعليمات البرمجية. يساعد التحليل الإحصائي في العثور على هذه القيم وفصلها عن النتائج الطبيعية.
اتخاذ قرارات مستنيرة: عند فهم نتائج الاختبارات بشكل إحصائي، يمكن اتخاذ قرارات أفضل بشأن تحسين التعليمات البرمجية أو إجراء التغييرات اللازمة لتحسين الأداء. على سبيل المثال، إذا كان هناك تباين كبير في النتائج، يمكن البحث عن السبب ومعرفة ما إذا كان يجب تحسين الخوارزمية أو النظام.
مقارنة بين الحلول المختلفة: عند مقارنة أكثر من طريقة لحل نفس المشكلة، يوفر التحليل الإحصائي المعلومات اللازمة لتحديد أي طريقة أكثر كفاءة. يساعد ذلك في اتخاذ قرارات بناءً على أرقام وليس مجرد تخمينات.
يعتمد هذا النوع من التحليل على المقارنة بين الطرق المختلفة. توفر المقارنات نظرة واضحة حول أي طريقة أداءها أفضل من ناحية سرعة التنفيذ، استخدام الذاكرة، أو أي معايير أخرى مهمة. على سبيل المثال: يمكن مقارنة بين خوارزميتين لحل نفس المشكلة.
هو الوقت الذي يحتاجه النظام لإنهاء تنفيذ عملية أو مجموعة عمليات.
معايير قياس الأداء:
ns (نانوسكند): النانوسكند هو جزء صغير جدًا من الثانية. الواحد نانوسكند يساوي 1 على مليار من الثانية (أي 10^-9 من الثانية).
ms (ميلي سكند): الميلي ثانية هي 1 على ألف من الثانية (أي 10^-3 من الثانية).
أنشئ مشروعًا جديدًا:
dotnet new console -n StringConcatenationBenchmarkDotNet
cd StringConcatenationBenchmarkDotNet
أضف حزمة BenchmarkDotNet:
dotnet add package BenchmarkDotNet
لنجرب دمج اسم أول مع اسم العائلة بطرق مختلفة:
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
using System.Text;
namespace StringConcatenationBenchmarkDotNet
{
public class StringConcatBenchmarks
{
// هذه هي بيانات الاختبار
private readonly string firstName = "Saif";
private readonly string lastName = "Saidi";
// استخدام عامل الجمع "+" لدمج النصوص
[Benchmark]
public string UsingPlusOperator_Benchmark()
{
return "Hello, " + firstName + " " + lastName + "!";
}
// استخدام String Interpolation لدمج النصوص
[Benchmark]
public string UsingStringInterpolation_Benchmark()
{
return $"Hello, {firstName} {lastName}!";
}
// استخدام String.Concat لدمج النصوص
[Benchmark]
public string UsingStringConcat_Benchmark()
{
return string.Concat("Hello, ", firstName, " ", lastName, "!");
}
// استخدام StringBuilder لدمج النصوص
[Benchmark]
public string UsingStringBuilder_Benchmark()
{
var sb = new StringBuilder();
sb.Append("Hello, ");
sb.Append(firstName);
sb.Append(" ");
sb.Append(lastName);
sb.Append("!");
return sb.ToString();
}
// استخدام String.Format لدمج النصوص
[Benchmark]
public string UsingStringFormat_Benchmark()
{
return string.Format("Hello, {0} {1}!", firstName, lastName);
}
}
}
📌 ملاحظة: قم دائمًا بتشغيل اختبارات الأداء في وضع "Release" للحصول على نتائج دقيقة.
public static void Main(stringargs)
{
BenchmarkRunner.Run<StringConcatBenchmarks>();
}
dotnet run -c Release
# أو قم بتفعيل خيار Release في Visual Studio وشغل المشروع
BenchmarkDotNet v0.13.12, OS Windows 10.0.19045.3930 (22H2/November2022Update)
Intel Core i7-8665U CPU 1.90GHz (Coffee Lake), 1 CPU, 8 logical and 4 physical cores
.NET SDK 9.0.104
| Method | Mean | Error | StdDev | Median |
|--------------------------------------|----------:|----------:|----------:|----------:|
| UsingPlusOperator_Benchmark | 42.79 ns | 1.140 ns | 3.324 ns | 41.98 ns |
| UsingStringInterpolation_Benchmark | 39.73 ns | 0.996 ns | 2.937 ns | 39.19 ns |
| UsingStringConcat_Benchmark | 32.25 ns | 0.206 ns | 0.182 ns | 32.19 ns |
| UsingStringBuilder_Benchmark | 65.86 ns | 2.461 ns | 7.022 ns | 63.93 ns |
| UsingStringFormat_Benchmark | 66.32 ns | 1.417 ns | 3.807 ns | 64.61 ns |
المقاييس الرئيسية التي تشرحها النتائج:
UsingStringConcat_Benchmark
، لأنها استغرقت أقل وقت (32.25 نانوثانية) وكان لديها أقل انحراف معياري (0.182 نانوثانية)، مما يعني أنها الأكثر ثباتًا أيضًا.UsingStringBuilder_Benchmark
و UsingStringFormat_Benchmark
، حيث استغرقتا حوالي 65.86 و 66.32 نانوثانية على التوالي، وهما من أكثر الطرق استغراقًا للوقت مقارنة بالطرق الأخرى.[Benchmark]
: تُستخدم لتحديد الدوال التي سيتم فحص أدائها.[MemoryDiagnoser]
: عند إضافة هذه السمة، يبدأ BenchmarkDotNet في تتبع كيفية توزيع الذاكرة خلال الاختبارات وعرض تقرير عن استخدام الذاكرة.[Params]
: تُستخدم لتحديد قيم مختلفة للمدخلات، لفحص نفس الدالة أكثر من مرة بمدخلات مختلفة.public class MyBenchmark
{
[Params(10, 100, 1000)] // قيم مختلفة للتجربة
public int Size;
[Benchmark]
public void MyTestMethod()
{
var list = new List<int>(Size);
// تنفيذ الاختبار مع حجم القائمة
}
}
[Setup]
, [GlobalSetup]
, [Cleanup]
:[Setup]
: يتم تنفيذه قبل كل اختبار، أي إذا كان هناك العديد من الاختبارات في الفئة، فسيتم تنفيذه عدة مرات.[GlobalSetup]
: يتم تنفيذه مرة واحدة فقط قبل جميع الاختبارات في الفئة. يُستخدم بشكل أساسي عند الحاجة إلى إجراء إعداد عام لمرة واحدة فقط.[Cleanup]
: يُستخدم لتنظيف البيانات أو تحرير الموارد بعد انتهاء جميع الاختبارات. يمكن استخدامه لإجراء إغلاق بعد تنفيذ الاختبارات.public class MyBenchmark
{
[Setup]
public void Setup()
{
// تجهيز البيانات أو البيئة للاختبارات
}
[Benchmark]
public void MyTestMethod()
{
// الاختبار هنا
}
}
ShortRunJob هو خيار سريع في BenchmarkDotNet لتقليل الوقت المستغرق في اختبارات الأداء، وهذا يسمح بالحصول على نتائج سريعة لتعليمات برمجية صغيرة أو سريعة التنفيذ، ولكن دقة الإحصائيات تكون أقل.
Job.Default
هو الإعداد الافتراضي في BenchmarkDotNet، حيث تُجرى الاختبارات بدقة مع عدد كبير من التكرارات والوقت اللازم للحصول على نتائج دقيقة إحصائيًا.
ShortRunJob
يعمل على تقليل مدة تنفيذ الاختبارات وعدد التكرارات، ويفضل استخدامه عند الحاجة إلى نتائج سريعة من اختبارات التعليمات البرمجية الصغيرة أو للتجارب السريعة.
[ShortRunJob] // اضف هذي الخاصية
public class ShortJobsBenchmarks
{
}
في BenchmarkDotNet، نستخدم ManualConfig
لإجراء إعدادات مخصصة والتحكم الكامل في كيفية تنفيذ الاختبارات. عادةً، عند استخدام BenchmarkDotNet، تُنفَّذ الاختبارات باستخدام الإعدادات الافتراضية، ولكن ManualConfig
يسمح بتخصيص مجموعة من الخيارات مثل إعدادات الوظائف (jobs)، وإضافة سمات إضافية، وتخصيص إعدادات التقارير، وخيارات أخرى كثيرة.
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
// ... باقي الكود
// إعداد التكوين اليدوي (ManualConfig)
var config = new ManualConfig()
.AddLogger(ConsoleLogger.Default); // إضافة مسجل لرؤية التقدم في وحدة التحكم
// تشغيل الاختبارات باستخدام التكوين المخصص
BenchmarkRunner.Run<StringConcatBenchmarks>(config);
AddLogger(ConsoleLogger.Default);
يمكنك استخدام أي مسجل لرؤية ما يحدث.
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
// ... باقي الكود
var config = new ManualConfig()
.AddLogger(ConsoleLogger.Default);
// تشغيل الاختبارات باستخدام التكوين المخصص
BenchmarkRunner.Run<StringConcatBenchmarks>(config);
Job.ShortRun
: يُستخدم ShortRunJob لتقليل وقت تنفيذ الاختبارات.Job.LongRun
: يُستخدم LongRun لزيادة وقت تنفيذ الاختبارات.AddJob(Job.Default.WithWarmupCount(5).WithIterationCount(10))
: يمكنك تحديد عدد مرات التسخين (Warm-up count) وعدد مرات التكرار (Iteration count) للاختبار.using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Jobs;
// ... باقي الكود
var config = new ManualConfig()
.AddLogger(ConsoleLogger.Default)
.AddJob(Job.ShortRun)
.AddJob(Job.Default.WithWarmupCount(5).WithIterationCount(10));
// تشغيل الاختبارات باستخدام التكوين المخصص
BenchmarkRunner.Run<StringConcatBenchmarks>(config);
يمكنك تخصيص الأعمدة المعروضة في جدول نتائج الاختبار باستخدام ManualConfig. على سبيل المثال، لإظهار أوقات التنفيذ الدنيا والقصوى، يمكنك استخدام الكود التالي:
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Loggers;
using BenchmarkDotNet.Running;
using BenchmarkDotNet.Columns; // تأكد من تضمين هذا النطاق للاسم
using BenchmarkDotNet.Jobs;
// ... باقي الكود
var config = new ManualConfig()
.AddLogger(ConsoleLogger.Default)
.AddJob(Job.ShortRun)
.AddJob(Job.Default.WithWarmupCount(5).WithIterationCount(10))
.AddColumn(StatisticColumn.Min) // لإظهار الحد الأدنى
.AddColumn(StatisticColumn.Max); // لإظهار الحد الأقصى
.AddColumnProvider(DefaultColumnProviders.Instance);// إضافة الأعمدة الافتراضية للتقارير
// تشغيل الاختبارات باستخدام التكوين المخصص
BenchmarkRunner.Run<StringConcatBenchmarks>(config);