Измерьте время выполнения в С#

180
5

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


Вариант 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");


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


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

спросил(а) 2010-10-11T05:42:00+04:00 9 лет, 2 месяца назад
8
Решение
166

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


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


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


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


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

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

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

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


ответил(а) 2010-10-11T05:49:00+04:00 9 лет, 2 месяца назад
Еще 7 ответов
115

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

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

ответил(а) 2010-10-11T05:58:00+04:00 9 лет, 2 месяца назад
88

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


Из MSDN страница:


Секундомер

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



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


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

ответил(а) 2010-10-11T05:47:00+04:00 9 лет, 2 месяца назад
81

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

ответил(а) 2010-10-11T05:46:00+04:00 9 лет, 2 месяца назад
47

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


например.


var tester = new PerformanceTester(() => SomeMethod());
tester.MeasureExecTime(1000);
Console.Writeline(string.Format("Executed in {0} milliseconds", tester.AverageTime.TotalMilliseconds));

ответил(а) 2010-10-11T09:12:00+04:00 9 лет, 2 месяца назад
45

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


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


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

ответил(а) 2010-10-11T05:58:00+04:00 9 лет, 2 месяца назад
32

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


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

}

ответил(а) 2013-10-12T03:05:00+04:00 6 лет, 1 месяц назад
31

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


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

ответил(а) 2012-03-16T19:33:00+04:00 7 лет, 8 месяцев назад
Ваш ответ
Введите минимум 50 символов
Чтобы , пожалуйста,
Выберите тему жалобы:

Другая проблема