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

StackOverflow https://stackoverflow.com/questions/28637

Вопрос

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

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

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 из-за работы, которая должна быть проделана с часовыми поясами, Летнее ВРЕМЯ и все такое.

Дата-время.UtcNow обычно имеет разрешение 15 мс.Видишь Запись в блоге Джона Чэпмена о нас DateTime.Now точность для получения отличного резюме.

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

Другие советы

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

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

Используйте систему.Диагностика.Класс секундомера.

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

// Do some code.

sw.Stop();

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

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

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

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

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

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

Самый прямой способ найти ошибку в потоке - запустить его, и пока он делает то, что заставляет вас ждать, остановите его с помощью клавиши pause или break.Проделайте это несколько раз.Если ваше узкое место занимает 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);
}

Так что это на самом деле не поможет вам узнать, сколько времени что-то заняло, просто то, что прошло определенное количество времени.

Таймер также доступен в качестве элемента управления в Системе.Windows.Формы...вы можете найти его в своем ящике для инструментов конструктора в 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);
    }
}

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

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

У группы Microsoft по шаблонам и практикам есть некоторые рекомендации по Руководство по тестированию производительности системы Visual Studio Team.

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

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

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

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

Редактировать:

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

Похоже, это хорошая статья

Способ, который я использую в своих программах, - это использование класса 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