Является ли DateTime.Now лучшим способом измерения производительности функции?

436

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

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

DateTime startTime = DateTime.Now;

// Some execution process

DateTime endTime = DateTime.Now;
TimeSpan totalTimeTaken = endTime.Subtract(startTime);
  • 0
    Кстати, если вы не ищете что-то быстрое и грязные счетчики производительности могут быть использованы.
  • 1
    Если вам нужна большая точность, используйте Stopwatch.GetTimestamp, в противном случае ответ хороший.
Показать ещё 3 комментария
Теги:
performance
timer
datetime

15 ответов

574
Лучший ответ

Нет, нет. Используйте StopwatchSystem.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.

  • 3
    Я бы поместил один PerformWork (); перед секундомером для «разогрева».
  • 2
    Также необходимо добавить рекомендацию о том, что если ваш PerformWork() очень короткий, вы сможете вызывать его повторно и вычислять среднее значение для пакета вызовов. Кроме того, рассчитывайте целую серию вызовов вместо того, чтобы запускать / останавливать ваш Stopwatch чтобы избежать строб-эффекта, который испортит ваши измерения времени.
Показать ещё 6 комментариев
84

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

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

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

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

  • 2
    ANTS еще работает с F #?
53

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

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

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

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

Изображение 1089

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

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

  • 0
    Первая ссылка не работает.
  • 1
    сломался да .. машина времени может показать это я бы догадался. Кстати, почему вы редактируете «тройку», я считаю, что в этом нет необходимости.
18

Полезно подтолкнуть ваш бенчмаркинг к полезному классу/методу. Класс 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);
}
  • 1
    Как насчет лучшей детализации? Многие вещи происходят менее чем за одну мс.
  • 0
    Затем верните свойство Elapsed, это TimeSpan. Я просто показываю вам шаблон. Удачи в реализации этого.
Показать ещё 1 комментарий
16

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

13

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

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

// Do some code.

sw.Stop();

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

Donto Секундомер, это лучше.

Что касается измерения производительности, вы должны также проверить, является ли ваш "//Некоторый процесс выполнения" очень коротким процессом.

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

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

9

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

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

Здесь более полное объяснение того, как и почему оно работает

7

@Шон Чамберс

FYI, класс .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

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

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 для получения точного счетчика производительности.

6

В Visual Studio Team System есть некоторые функции, которые могут помочь с этой проблемой. По сути, вы можете писать модульные тесты и смешивать их в разных сценариях, чтобы работать против вашего программного обеспечения как часть теста на нагрузку или нагрузку. Это может помочь определить области кода, которые наиболее сильно влияют на производительность ваших приложений.

Группа Microsoft "Модели и практики" имеет некоторые рекомендации в Руководство по тестированию производительности Team Team Team Visual Studio.

5

Я только что нашел сообщение в блоге Vance Morrison о классе CodeTimer, он написал, что упрощает использование StopWatch и делает некоторые аккуратные вещи на сторона.

4

Это недостаточно профессионально:

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, чтобы изменить управляемую кучу в известное состояние, и добавьте вызов сна, чтобы разные интервалы кода можно было легко разделить в профиле ETW.

4

Как я использую в своих программах, используется класс StopWatch, как показано здесь.

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;
  • 0
    Какой смысл int a = 5; ?
  • 1
    Понятия не имею. Должно быть, я добавил это по ошибке. Я теперь исправил проблему. Спасибо за указание на это.
4

Я сделал очень мало такого рода проверки производительности (я, как правило, просто думаю, что это медленно, сделать это быстрее), поэтому я почти всегда ушел с этим.

В Google обнаружено много ресурсов/статей для проверки производительности.

Многие упоминают использование pinvoke для получения информации о производительности. Многие материалы, которые я изучаю, действительно упоминают с использованием perfmon.

Edit:

Видите переговоры о StopWatch. Приятно! Я кое-чему чему научился:)

Это выглядит как хорошая статья

Ещё вопросы

Сообщество Overcoder
Наверх
Меню