Обчисліть час виконання методу


533

Можливий повтор:
Як визначити, як довго функціонує функція?

У мене є метод прийняття часу вводу / виводу, який копіює дані з місця в інше. Який найкращий і найбільш реальний спосіб розрахунку часу виконання? Thread? Timer? Stopwatch? Будь-яке інше рішення? Хочеться найточнішого і максимально стислого.

Відповіді:


1130

Stopwatch призначений для цієї мети і є одним з найкращих способів вимірювання виконання часу в .NET.

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

Не використовуйте DateTime для вимірювання часу виконання в .NET.


ОНОВЛЕННЯ:

Як вказував @ series0ne в розділі коментарів: Якщо ви хочете реально точно виміряти виконання деякого коду, вам доведеться використовувати лічильники продуктивності, вбудовані в операційну систему. Наступний відповідь містить хороший огляд.


2
Точно, а що з цим випадком: у мене є петля передбачення, яка має ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); внутрішню частину, але секундомір зупиняється, перш ніж все буде зроблено.
Махді Тахсілдарі

13
@DarinDimitrov - Секундомір не зовсім точний? пам’ятайте, що фоновий шум .NET (наприклад, JITing) викликає різний час виконання. Тому реально для точних вимірювань ОП повинен використовувати профайлер продуктивності.
Меттью Лейтон

3
@ series0ne, дуже хороший момент. Я оновлю свою відповідь, щоб включити ваш цінний коментар.
Дарин Димитров

7
@DarinDimitrov, я нещодавно провів інтерв'ю з дуже кваліфікованим старшим розробником. Він зазначив мені, що використання DateTimes насправді точніше, ніж використання секундоміра. Він сказав, що причина цього полягає в тому, що секундомір в .NET не враховує спорідненість процесора, і тому, якщо ваш потік переміщується з одного ядра в інше, секундомір не враховує час виконання через інші ядра; лише той, де нитка почала виконання. Яка ваша думка з цього приводу?
Меттью Лейтон

2
@ series0ne, те, що старший розробник розповів вам про секундомір та DateTime, абсолютно вірно. За винятком того, що з DateTime у вас недостатньо точності. Проблема полягає в тому, що в .NET немає такого класу, який би дозволяв вам усі ці функції.
Дарин Димитров

75

З особистого досвіду System.Diagnostics.Stopwatchклас може бути використаний для вимірювання часу виконання методу, проте ПЕРЕВАГА : Це не зовсім точно!

Розглянемо наступний приклад:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

Приклад результатів

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

Тепер вам цікаво; "ну чому це вперше пройшло 132 мс, а решту часу значно менше?"

Відповідь полягає в тому, Stopwatchщо не компенсує активність "фонового шуму" в .NET, наприклад, JITing. Тому перший раз, коли ви запускаєте свій метод, .NET JIT - це перший. Час, необхідний для цього, додається до часу виконання. Так само інші фактори також спричиняють різницю часу виконання.

Те, що ви справді повинні шукати для абсолютної точності, - це Профілювання продуктивності !

Погляньте на наступне:

RedGate ANTS Performance Profiler - комерційний продукт, але дає дуже точні результати. - Підвищення продуктивності ваших програм за допомогою .NET-профілювання

Ось стаття StackOverflow про профілювання: - Які є хороші .NET- профілі ?

Я також написав статтю про «Профілювання продуктивності» за допомогою секундоміра, яку ви можете подивитися - Профілювання продуктивності в .NET


2
@mahditahsildari Немає проблем. Радий, що можу допомогти! :-)
Меттью Лейтон

41
Я не впевнений, чому це приклад неточності . Секундомір точно вимірює загальну вартість першого дзвінка, що, безумовно, є те, що стосується клієнта, який збирається виконувати цей код. Їм не байдуже, чи заряджаються ці 132 мілісекунди на виконання методу чи на тремтіння, вони дбають про загальний час, що минув.
Ерік Ліпперт

2
@ series0ne Якщо ви дбаєте про ефективність циклу, то виміряйте продуктивність циклу. Не вважайте, що робити щось n разів означає, що це буде рівно n разів повільніше, ніж виконувати це один раз.
svick

3
По-перше, зразок коду повинен давати вихід із постійно зростаючим числом, оскільки StopWatch ніколи не скидається в циклі. І під "слід" я маю на увазі це так (я перевірив). Тож ваш вихід не відповідає коду. По-друге, коли я виправив код для зупинки / запису / скидання / запуску в циклі, перший вимір був таким же, як і решта. Я здогадуюсь, що ваш DoSomething робить щось довше, коли він працює. JIT може бути, а може і не бути причиною цього, але це не те, що секундомір впливає на вимірювання. Звідси -1.
ІЛІЯ БРУДНО

2
ІЛІЯ БРУДНО абсолютно коректний, я отримав однакові результати. @ series0ne, у вас є Console.WriteLine всередині циклу, записуючи повідомлення досі; оскільки ви зупиняєте годинник лише ПІСЛЯ закінчення циклу, він збільшується з часом із кожною ітерацією, тому ми повинні бачити щось на зразок 3, 6, 10, 12, 15 ..., як час накопичується над стратами.
Rui Miguel Pinheiro

29

StopWatch клас шукає найкраще рішення.

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

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

Також воно має статичне поле під назвою Stopwatch.IsHighResolution. Звичайно, це питання апаратного забезпечення та операційної системи.

Вказує, чи заснований таймер на лічильнику продуктивності високої роздільної здатності.


18

Якщо ви зацікавлені в розумінні продуктивності, найкраща відповідь - використовувати профілер.

В іншому випадку System.Diagnostics.StopWatch забезпечує таймер високої роздільної здатності.


Абсолютно правильно! Мені трохи неприємно, що так багато тут запропонували використовувати Секундомір, оскільки це не зовсім точно. Однак, як ви запропонували використовувати програміст Performance, це правильний спосіб зробити це! +1
Меттью Лейтон

7

StopWatch використовуватиме лічильник високої роздільної здатності

Секундомір вимірює минулий час шляхом підрахунку таймерів у базовому механізмі таймера. Якщо встановлене обладнання та операційна система підтримують лічильник продуктивності високої роздільної здатності, то секундомір класу використовує цей лічильник для вимірювання минулого часу. В іншому випадку клас секундомір використовує системний таймер для вимірювання минулого часу. Використовуйте поля Frequency та IsHighResolution, щоб визначити точність та роздільну здатність часу синхронізації.

Якщо ви вимірюєте IO, то на ваші цифри, ймовірно, впливатимуть зовнішні події, і я б дуже переживав. точність (як ви вказали вище). Натомість я б провів ряд вимірювань і розглядав середнє значення та розподіл цих показників.


0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.