Рассчитать время выполнения метода

533

Возможный дубликат:
Как измерить продолжительность работы функции?

У меня есть метод ввода-вывода времени, который копирует данные из одного места в другое. Какой самый лучший и самый реальный способ расчета времени выполнения? Thread? Timer? Stopwatch? Любое другое решение? Я хочу самый точный и максимально краткий.

Махди Тахсилдари
источник

Ответы:

1131

Stopwatch предназначен для этой цели и является одним из лучших способов измерения времени выполнения в .NET.

var watch = System.Diagnostics.Stopwatch.StartNew();
// the code that you want to measure comes here
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;

Не используйте DateTime для измерения времени выполнения в .NET.


ОБНОВИТЬ:

Как отметил @ series0ne в разделе комментариев: если вы хотите действительно точного измерения выполнения некоторого кода, вам придется использовать счетчики производительности, встроенные в операционную систему. Следующий ответ содержит хороший обзор.

Дарин димитров
источник
2
Точно, и что относительно этого случая: у меня есть цикл foreach, у которого есть ThreadPool.QueueUserWorkItem(delegate { CopyFiles(folder, dest); }); внутренняя часть, но секундомер останавливается прежде, чем все будет сделано.
Махди Тахсилдари
13
@DarinDimitrov - Секундомер не совсем точен? помните, что фоновый шум .NET (такой как JITing) вызывает различное время выполнения. Поэтому реально для точных измерений OP должен использовать профилировщик производительности.
Мэтью Лейтон
3
@ series0ne, очень хорошая мысль. Я обновлю свой ответ, чтобы включить ваш ценный комментарий.
Дарин Димитров
7
@DarinDimitrov, у меня недавно было интервью с очень опытным старшим разработчиком. Он указал мне, что использование DateTimes на самом деле более точно, чем использование StopWatch. Он сказал, что причина этого в том, что секундомер в .NET не учитывает привязку к процессору, и поэтому, если ваш поток перемещается из одного ядра в другое, секундомер не учитывает время выполнения в других ядрах; только тот, где поток начал выполнение. Каково ваше мнение по этому поводу?
Мэтью Лейтон
2
@ series0ne, то, что старший разработчик рассказал вам о секундомере и DateTime, абсолютно верно. Кроме того, что с DateTime вам не хватает точности. Проблема в том, что в .NET нет такого класса, который позволял бы вам использовать все эти функции.
Дарин Димитров
75

Исходя из личного опыта, System.Diagnostics.Stopwatchкласс можно использовать для измерения времени выполнения метода, однако, ВНИМАНИЕ : он не совсем точен!

Рассмотрим следующий пример:

Stopwatch sw;

for(int index = 0; index < 10; index++)
{
    sw = Stopwatch.StartNew();
    DoSomething();
    Console.WriteLine(sw.ElapsedMilliseconds);
}

sw.Stop();

Пример результатов

132ms
4ms
3ms
3ms
2ms
3ms
34ms
2ms
1ms
1ms

Теперь вам интересно; "Ну, почему это заняло 132 мс в первый раз, и значительно меньше в остальное время?"

Ответ заключается в том, Stopwatchчто не компенсирует активность «фонового шума» в .NET, такую ​​как JITing. Поэтому при первом запуске вашего метода, .NET JIT первым. Время, необходимое для этого, добавляется ко времени выполнения. Точно так же другие факторы также могут привести к изменению времени выполнения.

Что вам действительно нужно для абсолютной точности, так это профилирование производительности !

Посмотрите на следующее:

RedGate ANTS Performance Profiler является коммерческим продуктом, но дает очень точные результаты. - Повысьте производительность своих приложений с помощью профилирования .NET

Вот статья StackOverflow по профилированию: - Что такое хорошие профилировщики .NET?

Я также написал статью о профилировании производительности с помощью секундомера, на которую вы можете взглянуть - Профилирование производительности в .NET

Мэтью Лейтон
источник
2
@mahditahsildari Нет проблем. Рад, что смог помочь! :-)
Мэтью Лейтон,
41
Я не уверен, почему это пример неточности . Секундомер точно измеряет общую стоимость первого звонка, что, безусловно, относится к клиенту, который будет использовать этот код. Их не волнует, будут ли эти 132 миллисекунды начисляться на выполнение метода или дрожание, они заботятся об общем прошедшем времени.
Эрик Липперт
2
@ series0ne Если вы заботитесь о производительности цикла, измерьте производительность цикла. Не просто предполагайте, что выполнение чего-либо n раз означает, что это будет ровно в n раз медленнее, чем выполнение этого один раз.
svick
3
Во-первых, пример кода должен производить вывод с постоянно увеличивающимся числом, так как StopWatch никогда не сбрасывается в цикле. И под «должен» я имею в виду это (я проверил). Таким образом, ваш вывод не соответствует коду. Во-вторых, когда я исправил код для выполнения остановки / записи / сброса / запуска в цикле, первое измерение было таким же, как и остальные. Я предполагаю, что ваш DoSomething делает что-то дольше при первом запуске. JIT может быть или не быть причиной этого, но дело не в том, что секундомер влияет на измерение. Отсюда -1.
ИЛЬЯ БРУДНО
2
Илья Бродно абсолютно прав, я получил те же результаты. @ series0ne, у вас есть Console.WriteLine внутри цикла, пока вы пишете мс; поскольку вы останавливаете часы только ПОСЛЕ окончания цикла, он увеличивается с течением времени с каждой итерацией, поэтому мы должны видеть что-то вроде 3, 6, 10, 12, 15 ... по мере того, как время накапливается во время выполнения.
Руи Мигель Пинейро
29

StopWatch класс ищет ваше лучшее решение.

Stopwatch sw = Stopwatch.StartNew();
DoSomeWork();
sw.Stop();

Console.WriteLine("Time taken: {0}ms", sw.Elapsed.TotalMilliseconds);

Также у него есть статическое поле с именем Stopwatch.IsHighResolution. Конечно, это проблема оборудования и операционной системы.

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

Soner Gönül
источник
18

Если вы заинтересованы в понимании производительности, лучший ответ - использовать профилировщик.

В противном случае System.Diagnostics.StopWatch предоставляет таймер высокого разрешения.

Джефф Фостер
источник
Абсолютно правильно! Я немного разочарован тем, что многие здесь предложили использовать секундомер, поскольку он не совсем точен. Однако, как вы предложили использовать профилировщик производительности, это правильный способ сделать это! +1
Мэтью Лейтон
7

StopWatch будет использовать счетчик высокого разрешения

Секундомер измеряет прошедшее время, подсчитывая отметки времени в базовом механизме таймера. Если установленное оборудование и операционная система поддерживают счетчик производительности с высоким разрешением, то класс секундомера использует этот счетчик для измерения прошедшего времени. В противном случае класс Секундомер использует системный таймер для измерения прошедшего времени. Используйте поля Frequency и IsHighResolution, чтобы определить точность и разрешение реализации синхронизации секундомера.

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

Брайан Агнью
источник
0
 using System.Diagnostics;
 class Program
 {
    static void Test1()
    {
        for (int i = 1; i <= 100; i++)
        {
            Console.WriteLine("Test1 " + i);
        }
    }
  static void Main(string[] args)
    {

        Stopwatch sw = new Stopwatch();
        sw.Start();
        Test1();
        sw.Stop();
        Console.WriteLine("Time Taken-->{0}",sw.ElapsedMilliseconds);
   }
 }
М-р. Ракибуз Султан
источник