سؤال

أحتاج إلى إيجاد عنق الزجاجة وأحتاج إلى قياس الوقت بدقة قدر الإمكان.

هل مقتطف الكود التالي هو أفضل طريقة لقياس الأداء؟

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
هل كانت مفيدة؟

المحلول

لا ليس كذلك.استخدم ال ساعة التوقيف (في System.Diagnostics)

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

تتحقق ساعة الإيقاف تلقائيًا من وجود مؤقتات عالية الدقة.

ومن الجدير بالذكر أن DateTime.Now غالبًا ما يكون أبطأ قليلاً من DateTime.UtcNow بسبب العمل الذي يجب القيام به مع المناطق الزمنية، التوقيت الصيفي وكذا.

تبلغ دقة DateTime.UtcNow عادةً 15 مللي ثانية.يرى مشاركة مدونة جون تشابمان عن DateTime.Now الدقة لملخص كبير.

التوافه مثيرة للاهتمام:ساعة الإيقاف تتراجع DateTime.UtcNow إذا كان جهازك لا يدعم عداد التردد العالي.يمكنك التحقق لمعرفة ما إذا كانت ساعة الإيقاف تستخدم الأجهزة لتحقيق دقة عالية من خلال النظر إلى المجال الثابت ساعة توقيت.IsHighResolution.

نصائح أخرى

إذا كنت تريد شيئًا سريعًا وقذرًا، فأنا أقترح استخدام ساعة الإيقاف بدلاً من ذلك للحصول على درجة أكبر من الدقة.

Stopwatch sw = new Stopwatch();
sw.Start();
// Do Work
sw.Stop();

Console.WriteLine("Elapsed time: {0}", sw.Elapsed.TotalMilliseconds);

وبدلاً من ذلك، إذا كنت بحاجة إلى شيء أكثر تعقيدًا، فمن المحتمل أن تفكر في استخدام ملف تعريف تابع لجهة خارجية مثل النمل.

هذا المقال يقول أنه عليك أولاً مقارنة ثلاثة بدائل، Stopwatch, DateTime.Now و DateTime.UtcNow.

ويوضح أيضًا أنه في بعض الحالات (عند عدم وجود عداد الأداء) تستخدم ساعة الإيقاف DateTime.UtcNow + بعض المعالجة الإضافية.ولهذا السبب، من الواضح أنه في هذه الحالة فإن DateTime.UtcNow هو الخيار الأفضل (لأن الآخرين يستخدمونه + بعض المعالجة)

ومع ذلك، كما اتضح، فإن العداد موجود دائمًا تقريبًا - انظر شرح عن عداد الأداء عالي الدقة ووجوده المتعلق بـ .NET Stopwatch؟.

هنا رسم بياني للأداء.لاحظ مدى انخفاض تكلفة الأداء لدى UtcNow مقارنة بالبدائل:

Enter image description here

المحور X هو حجم بيانات العينة، والمحور Y هو الوقت النسبي للمثال.

شئ واحد Stopwatch الأفضل هو أنه يوفر قياسات زمنية ذات دقة أعلى.آخر هو طبيعة أكثر OO.ومع ذلك، إنشاء غلاف OO حولها UtcNow لا يمكن أن يكون صعبا.

من المفيد دفع كود القياس الخاص بك إلى فئة/طريقة فائدة.ال StopWatch الطبقة لا تحتاج إلى أن تكون Disposed أو Stopped على خطأ.لذلك، أبسط رمز ل وقت بعض فعل يكون

public partial class With
{
    public static long Benchmark(Action action)
    {
        var stopwatch = Stopwatch.StartNew();
        action();
        stopwatch.Stop();
        return stopwatch.ElapsedMilliseconds;
    }
}

نموذج رمز الاتصال

public void Execute(Action action)
{
    var time = With.Benchmark(action);
    log.DebugFormat(“Did action in {0} ms.”, time);
}

هنا هو إصدار طريقة التمديد

public static class Extensions
{
    public static long Benchmark(this Action action)
    {
        return With.Benchmark(action);
    }
}

ونموذج رمز الاتصال

public void Execute(Action action)
{
    var time = action.Benchmark()
    log.DebugFormat(“Did action in {0} ms.”, time);
}

ال ساعة التوقيف ستكون الوظيفة أفضل (دقة أعلى).أوصي أيضًا بتنزيل أحد ملفات التعريف الشائعة (دوتتريس و النمل هي أكثر الأشياء التي استخدمتها..النسخة التجريبية المجانية لـ DotTrace تعمل بكامل طاقتها ولا تتذمر مثل بعض الإصدارات الأخرى).

استخدم فئة System.Diagnostics.Stopwatch.

Stopwatch sw = new Stopwatch();
sw.Start();

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.

كما سبق ساعة الإيقاف، فهي أفضل بكثير.

فيما يتعلق بقياس الأداء، يجب عليك أيضًا التحقق مما إذا كانت "// بعض عمليات التنفيذ" هي عملية قصيرة جدًا.

ضع في اعتبارك أيضًا أن التشغيل الأول لـ "// بعض عمليات التنفيذ" قد يكون أبطأ بكثير من عمليات التشغيل اللاحقة.

عادةً ما أقوم باختبار الطريقة عن طريق تشغيلها 1000 مرة أو 1000000 مرة في حلقة وأحصل على بيانات أكثر دقة من تشغيلها مرة واحدة.

هذه كلها طرق رائعة لقياس الوقت، ولكنها ليست سوى طريقة غير مباشرة للغاية للعثور على عنق الزجاجة (الاختناقات).

الطريقة الأكثر مباشرة للعثور على عنق الزجاجة في سلسلة ما هي تشغيلها، وأثناء القيام بكل ما يجعلك تنتظر، قم بإيقافها باستخدام مفتاح الإيقاف المؤقت أو التوقف.افعل هذا عدة مرات.إذا استغرق عنق الزجاجة الخاص بك X% من الوقت، فإن X% هو احتمال اكتشافك له متلبسًا في كل لقطة.

فيما يلي شرح أكثر اكتمالاً لكيفية عمله ولماذا

@شون تشامبرز

لمعلوماتك، فئة .NET Timer ليست مخصصة للتشخيصات، فهي تنشئ أحداثًا على فترات زمنية محددة مسبقًا، مثل هذا (من MSDN):

System.Timers.Timer aTimer;
public static void Main()
{
    // Create a timer with a ten second interval.
    aTimer = new System.Timers.Timer(10000);

    // Hook up the Elapsed event for the timer.
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

    // Set the Interval to 2 seconds (2000 milliseconds).
    aTimer.Interval = 2000;
    aTimer.Enabled = true;

    Console.WriteLine("Press the Enter key to exit the program.");
    Console.ReadLine();
}

// Specify what you want to happen when the Elapsed event is 
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}

لذا فإن هذا لا يساعدك حقًا في معرفة المدة التي استغرقها شيء ما، بل فقط لقد مر قدر معين من الوقت.

يتم عرض المؤقت أيضًا كعنصر تحكم في System.Windows.Forms...يمكنك العثور عليه في صندوق أدوات المصمم الخاص بك في VS05/VS08

هذه هي الطريقة الصحيحة:

using System;
using System.Diagnostics;

class Program
{
    public static void Main()
    {
        Stopwatch stopWatch = Stopwatch.StartNew();

            // some other code

        stopWatch.Stop();

        // this not correct to get full timer resolution
        Console.WriteLine("{0} ms", stopWatch.ElapsedMilliseconds);

        // Correct way to get accurate high precision timing
        Console.WriteLine("{0} ms", stopWatch.Elapsed.TotalMilliseconds);
    }
}

لمزيد من المعلومات اذهب من خلال استخدم Stopwatch بدلاً من DataTime للحصول على عداد أداء دقيق.

نظام فريق الاستوديو المرئي يحتوي على بعض الميزات التي قد تساعد في حل هذه المشكلة.يمكنك بشكل أساسي كتابة اختبارات الوحدة ومزجها في سيناريوهات مختلفة لتشغيلها على برنامجك كجزء من اختبار الضغط أو التحميل.قد يساعد هذا في تحديد مجالات التعليمات البرمجية التي تؤثر بشكل أكبر على أداء تطبيقاتك.

تحتوي مجموعة الأنماط والممارسات الخاصة بشركة Microsoft على بعض الإرشادات إرشادات اختبار أداء نظام فريق Visual Studio.

لقد وجدت للتو منشورًا في مدونة فانس موريسون حول فئة CodeTimer كتب أن يجعل استخدام StopWatch أسهل ويقوم ببعض الأشياء الأنيقة على الجانب.

لقد قمت بالقليل جدًا من هذا النوع من فحص الأداء (أميل إلى التفكير فقط "هذا بطيء، اجعله أسرع") لذلك كنت أتبع هذا دائمًا تقريبًا.

تكشف Google عن الكثير من الموارد/المقالات للتحقق من الأداء.

يذكر الكثير استخدام pinvoc للحصول على معلومات الأداء.الكثير من المواد التي أدرسها لا تذكر سوى استخدام البيرفمون..

يحرر:

شاهدت محادثات StopWatch..لطيف - جيد!لقد تعلمت شيئا :)

هذا يبدو وكأنه مقالة جيدة

الطريقة التي أستخدمها داخل برامجي هي استخدام فئة StopWatch كما هو موضح هنا.

Stopwatch sw = new Stopwatch();
sw.Start();


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;

هذا ليس احترافيًا بما فيه الكفاية:

Stopwatch sw = Stopwatch.StartNew();
PerformWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

الإصدار الأكثر موثوقية هو:

PerformWork();

int repeat = 1000;

Stopwatch sw = Stopwatch.StartNew();
for (int i = 0; i < repeat; i++)
{
   PerformWork();
}

sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds / repeat);

في الكود الحقيقي الخاص بي، سأضيف استدعاء GC.Collect لتغيير الكومة المُدارة إلى حالة معروفة، وأضيف استدعاء Sleep بحيث يمكن فصل فترات زمنية مختلفة من التعليمات البرمجية بسهولة في ملف تعريف ETW.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top