Сведения о вопросе

rjevskii

05:46, 28th August, 2020

Теги

c#   .net   performance   datetime   timer    

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

Просмотров: 544   Ответов: 15

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

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

DateTime startTime = DateTime.Now;

// Some execution process

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



  Сведения об ответе

P_S_S

04:27, 17th August, 2020

Нет, это не так. Используйте секундомер (in 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 ms. см. Запись В блоге Джона Чапмена о точности DateTime.Now для получения отличного резюме.

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


  Сведения об ответе

prince

16:27, 8th August, 2020

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

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

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

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


  Сведения об ответе

screen

21:06, 1st October, 2020

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

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

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

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

Enter image description here

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

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


  Сведения об ответе

VERSUION

01:33, 3rd August, 2020

Полезно поместить свой бенчмаркинговый код в служебную программу class/method. класс 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);
}


  Сведения об ответе

JUST___

20:32, 2nd August, 2020

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


  Сведения об ответе

piter

17:51, 19th August, 2020

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

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

// Do some code.

sw.Stop();

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


  Сведения об ответе

P_S_S

09:16, 2nd August, 2020

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

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

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

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


  Сведения об ответе

padenie

15:29, 21st August, 2020

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

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

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


  Сведения об ответе

dumai

07:36, 18th August, 2020

@ Sean Chambers

FYI, класс таймера .NET не предназначен для диагностики, он генерирует события с заданным интервалом, как это (от 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


  Сведения об ответе

qwerty101

06:59, 23rd August, 2020

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

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


  Сведения об ответе

LAST

04:19, 4th August, 2020

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

Microsoft ' Patterns and Practices group имеет некоторые рекомендации в руководстве по тестированию производительности командной системы Visual Studio .


  Сведения об ответе

JUST___

16:40, 5th August, 2020

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


  Сведения об ответе

pumpa

03:54, 25th August, 2020

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

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

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

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

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

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


  Сведения об ответе

davran

04:40, 11th August, 2020

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

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


// Critical lines of code

long elapsedMs = sw.Elapsed.TotalMilliseconds;


  Сведения об ответе

lool

15:45, 15th August, 2020

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

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.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться