DateTime.Now лучший способ измерить производительность функции? - PullRequest
457 голосов
/ 26 августа 2008

Мне нужно найти узкое место и нужно максимально точно измерить время.

Является ли следующий фрагмент кода лучшим способом измерения производительности?

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);

Ответы [ 15 ]

633 голосов
/ 26 августа 2008

Нет, это не так. Используйте Секундомер System.Diagnostics)

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

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

Секундомер автоматически проверяет наличие высокоточных таймеров.

Стоит отметить, что DateTime.Now часто немного медленнее, чем DateTime.UtcNow из-за работы, выполняемой с часовыми поясами, DST и т.п.

DateTime.UtcNow обычно имеет разрешение 15 мс. См. сообщение в блоге Джона Чэпмена о DateTime.Now точности для хорошего резюме.

Интересные мелочи: секундомер возвращается к DateTime.UtcNow, если ваше оборудование не поддерживает высокочастотный счетчик. Вы можете проверить, использует ли секундомер аппаратное обеспечение для достижения высокой точности, посмотрев на статическое поле Stopwatch.IsHighResolution .

90 голосов
/ 26 августа 2008

Если вы хотите что-то быстрое и грязное, я бы предложил вместо этого использовать секундомер для большей точности.

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

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

В качестве альтернативы, если вам нужно что-то более сложное, вам, вероятно, следует рассмотреть возможность использования стороннего профилировщика, например ANTS .

54 голосов
/ 08 августа 2011

В этой статье говорится, что в первую очередь вам необходимо сравнить три варианта: Stopwatch, DateTime.Now И DateTime.UtcNow.

Это также показывает, что в некоторых случаях (когда счетчик производительности не существует) секундомер использует DateTime.UtcNow + некоторая дополнительная обработка. Из-за этого очевидно, что в этом случае DateTime.UtcNow является лучшим вариантом (потому что другие используют его + некоторая обработка)

Однако, как выясняется, счетчик почти всегда существует - см. Пояснение о счетчике производительности с высоким разрешением и его наличии, связанном с .NET Stopwatch? .

Вот график производительности. Обратите внимание, как низкая стоимость производительности UtcNow по сравнению с альтернативами:

Enter image description here

Ось X - это размер выборки, а ось Y - относительное время примера.

Одна вещь Stopwatch лучше в том, что она обеспечивает измерения времени с более высоким разрешением. Другой - это его более оо-природа. Тем не менее, создание OO-оболочки вокруг UtcNow не может быть трудным.

18 голосов
/ 02 сентября 2008

Полезно перенести код сравнения в класс / метод утилиты. Класс 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);
}
16 голосов
/ 26 августа 2008

Функциональность секундомер была бы лучше (более высокая точность). Я также рекомендовал бы просто загрузить один из популярных профилировщиков, хотя ( DotTrace и ANTS - это те, которые я использовал больше всего ... бесплатная пробная версия для DotTrace полностью функциональна и не ворчит, как некоторые другие).

13 голосов
/ 26 августа 2008

Используйте класс System.Diagnostics.Stopwatch.

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

// Do some code.

sw.Stop();

// sw.ElapsedMilliseconds = the time your "do some code" took.
10 голосов
/ 30 августа 2008

То же самое, секундомер намного лучше.

Что касается измерения производительности, вам также следует проверить, является ли ваш "// Some Execution Process" очень коротким процессом.

Также имейте в виду, что первый запуск вашего "// Some Execution Process" может быть намного медленнее, чем последующие.

Обычно я тестирую метод, выполняя его 1000 раз или 1000000 раз в цикле, и получаю гораздо более точные данные, чем один раз.

9 голосов
/ 27 января 2009

Все это отличные способы измерения времени, но это только очень косвенный способ найти узкие места.

Самый прямой способ найти узкое место в потоке - это запустить его, и пока он делает все, что заставляет вас ждать, остановите его клавишей паузы или прерывания. Сделайте это несколько раз. Если ваше узкое место занимает X% времени, X% - это вероятность того, что вы поймаете его в действии на каждом снимке.

Вот более полное объяснение того, как и почему это работает

7 голосов
/ 26 августа 2008

@ Шон Чемберс

К вашему сведению, класс .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

6 голосов
/ 06 марта 2011

Это правильный путь:

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);
    }
}

Для получения дополнительной информации пройдите Используйте секундомер вместо DataTime для получения точного счетчика производительности .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...