Измерьте время выполнения в C # - PullRequest
36 голосов
/ 11 октября 2010

Я хочу измерить выполнение фрагмента кода, и мне интересно, какой лучший способ сделать это?

Вариант 1:

DateTime StartTime = DateTime.Now;

//Code

TimeSpan ts = DateTime.Now.Subtract(StartTime);
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
Console.WriteLine(elapsedTime, "RunTime");

Вариант 2: используя System.Diagnostics;

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

    //Code

    stopWatch.Stop();
    // Get the elapsed time as a TimeSpan value.
    TimeSpan ts = stopWatch.Elapsed;

    // Format and display the TimeSpan value.
    string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
        ts.Hours, ts.Minutes, ts.Seconds,
        ts.Milliseconds / 10);
    Console.WriteLine(elapsedTime, "RunTime");

Это не просто для сравнительного анализа, это фактически часть приложения. Время, необходимое для выполнения функции, является релевантными данными. Однако он не должен быть атомарным или сверхточным.

Какой вариант лучше для производственного кода, или кто-то еще использует что-то другое и, возможно, лучше?

Ответы [ 8 ]

28 голосов
/ 11 октября 2010

Класс Stopwatch специально разработан для измерения прошедшего времени и может (при наличии на вашем оборудовании) обеспечивать хорошую детализацию / точность с использованием базового высокочастотного аппаратного таймера.Так что это, кажется, лучший выбор.

Свойство IsHighResolution можно использовать для определения доступности синхронизации с высоким разрешением.Согласно документации, этот класс предлагает оболочку для «лучших из доступных» Win32 API для точного определения времени:

В частности, вместо неуправляемого можно использовать поле Frequency и метод GetTimestamp.Win32 API QueryPerformanceFrequency и QueryPerformanceCounter.

Подробная информация об этих Win32 API [здесь] и в связанных документах MSDN 2 .

Таймер высокого разрешения

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

Если в системе существует счетчик производительности с высоким разрешением, вы можете использовать функцию QueryPerformanceFrequency для выражениячастота, в счетах в секунду.Значение счетчика зависит от процессора.Например, на некоторых процессорах счетчик может быть тактовой частотой тактовой частоты процессора.

Функция QueryPerformanceCounter извлекает текущее значение счетчика производительности с высоким разрешением.Вызывая эту функцию в начале и конце фрагмента кода, приложение по существу использует счетчик в качестве таймера высокого разрешения.Например, предположим, что QueryPerformanceFrequency указывает, что частота счетчика производительности с высоким разрешением составляет 50 000 отсчетов в секунду.Если приложение вызывает QueryPerformanceCounter непосредственно перед и сразу после секции кода, которая будет синхронизирована, значения счетчиков могут составлять 1500 и 3500 соответственно.Эти значения указывают, что 0,04 секунды (2000 отсчетов) истекли во время выполнения кода.

13 голосов
/ 11 октября 2010

Дело не только в том, что StopWatch является более точным, но также в том, что DateTime.Now даст неправильные результаты в некоторых обстоятельствах.

Рассмотрим, что происходит, например, при переходе на летнее время, используяDateTime.Now может дать отрицательный ответ!

6 голосов
/ 11 октября 2010

Я обычно использую StopWatch для такой ситуации.

С MSDN страница:

StopWatch

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

В следующем посте я использую его для сравнения времени выполнения LINQ против PLINQ:

Параллельное LINQ (PLINQ) с Visual Studio 2010

5 голосов
/ 11 октября 2010

Никто не повредит производительности, потому что вы говорите, что это не так критично.Секундомер кажется более подходящим - вы только вычитаете время от времени, а не одну дату из другой.Для работы с датами требуется немного больше памяти и процессорного времени.Есть также способы сделать код чище, если вы планируете использовать его в нескольких местах.На ум приходит перегрузка using.Я буду искать пример.Хорошо, код украден у:

http://stevesmithblog.com/blog/great-uses-of-using-statement-in-c/

public class ConsoleAutoStopWatch : IDisposable
{
    private readonly Stopwatch _stopWatch;

    public ConsoleAutoStopWatch()
    {
        _stopWatch = new Stopwatch();
        _stopWatch.Start();
    }

    public void Dispose()
    {
        _stopWatch.Stop();
        TimeSpan ts = _stopWatch.Elapsed;

        string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}.{3:00}",
                                           ts.Hours, ts.Minutes, ts.Seconds,
                                           ts.Milliseconds / 10);
        Console.WriteLine(elapsedTime, "RunTime");
    }
}

private static void UsingStopWatchUsage()
{
    Console.WriteLine("ConsoleAutoStopWatch Used: ");
    using (new ConsoleAutoStopWatch())
    {
        Thread.Sleep(3000);
    }
}
1 голос
/ 11 октября 2010

У меня есть небольшой класс, чтобы делать подобные вещи ad hoc. Он использует класс секундомера - c # микро-тестирование производительности .

например.

var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));
1 голос
/ 11 октября 2010

И то и другое, вероятно, подойдет для ваших нужд, но я бы сказал, используйте StopWatch. Зачем? Потому что это предназначено для задачи, которую вы делаете.

У вас есть один класс, созданный для возврата текущей даты / времени, который может быть использован для измерения времени, и у вас есть один класс, специально предназначенный для измерения времени.

В этом случае различия действительно существуют, только если вам нужна точность в миллисекундах (в этом случае StopWatch точнее), но в качестве общего принципа, если инструмент существует специально для задачи, которую вы ищете, тогда лучше один для использования.

0 голосов
/ 12 октября 2013

Я взял ответ Хэмиша, упростил его и сделал его более общим в случае, если вам нужно войти в другое место:

public class AutoStopWatch : Stopwatch, IDisposable {

    public AutoStopWatch() {
        Start();
    }

    public virtual void Dispose() {
        Stop();
    }
}

 public class AutoStopWatchConsole : AutoStopWatch {

    private readonly string prefix;

    public AutoStopWatchConsole(string prefix = "") {
        this.prefix = prefix;
    }

    public override void Dispose() {
        base.Dispose();

        string format = Elapsed.Days > 0 ? "{0} days " : "";
        format += "{1:00}:{2:00}:{3:00}.{4:00}";

        Console.WriteLine(prefix + " " + format.Format(Elapsed.Days, Elapsed.Hours, Elapsed.Minutes, Elapsed.Seconds, Elapsed.Milliseconds / 10));
    }
}

private static void Usage() {

    Console.WriteLine("AutoStopWatch Used: ");
    using (var sw = new AutoStopWatch()) {
        Thread.Sleep(3000);

        Console.WriteLine(sw.Elapsed.ToString("h'h 'm'm 's's'"));
    }

    Console.WriteLine("AutoStopWatchConsole Used: ");
    using (var sw = new AutoStopWatchConsole()) {
        Thread.Sleep(3000);
    }

}
0 голосов
/ 16 марта 2012

Используйте код ниже

DateTime dExecutionTime;
dExecutionTime = DateTime.Now;
      TimeSpan span = DateTime.Now.Subtract(dExecutionTime);
                  lblExecutinTime.Text = "total time taken " +   Math.Round(span.TotalMinutes,2) + " minutes .   >>---> " + DateTime.Now.ToShortTimeString();
...