DateTime.Now vs. Stopwatch

Читая книгу Андрея Акиньшина “Профессиональный бенчмарк” решил проверять приводимые в книге примеры на практике (автор сам так рекомендует). Начал, конечно же, со столь любимого мною в прошлом “бенчмарка новичков”: измерения DateTime.Now до и после испытуемого на скорость кода и последующего вычисления разности.

Но вот в чем засада по словам автора: для Windows10 частота обновления DateTime по умолчанию 64Гц. А это значит, что новое значение получается с интервалами 15,625 мс и это же значение составляет точность подхода с DateTime. Т.е для всех операций, которые выполнятся быстрее 15,625 мс мы получим значение времени выполнения интересующего кода равное 0, либо, если не повезёт, то 15,625 мс. Такая точность не всегда бывает недопустима, особенно если испытуемый на скорость код выполняется быстрее.

1
2
3
4
5
6
var list = Enumerable.Range(0, 10000).ToList();
DateTime start = DateTime.Now;
list.Sort();
DateTime end = DateTime.Now;
TimeSpan elapsedTime = end - start;
Console.WriteLine(elapsedTime.TotalMilliseconds);

Пробую код из книги на Windows10 C#6.0 и получаю результаты около 4,5 мс. Предсказанный Андреем 0 никак получить не удалось, как и собственно 15,625 мс.

Двигаемся дальше.

По словам автора, лучшей альтернативой DateTime.Now является класс System.Diagnostics.Stopwatch. Типичное разрешение Stopwatch в Windows10 составляет величину порядка 300-500 нс.

1
2
3
4
5
6
var list = Enumerable.Range(0, 10000).ToList();
var stopwatch = System.Diagnostics.Stopwatch.StartNew();
list.Sort();
stopwatch.Stop();
TimeSpan elapsedTime = stopwatch.Elapsed;
Console.WriteLine(elapsedTime.TotalMilliseconds);

Этот код на машине автора выдавал результат в 0,05 мс. Однако на моей машине средний результат крутился в районе 0,491 мс, что в 10 раз больше, чем ожидалось!

Никакого анализа причин этих цифр пока привести не могу. Только начинаю погружаться в тонкости бенчмарка. Однако отмечу, что поведение DateTime.Now на моей машине много точнее, чем на машине автора, а System.Diagnostics.Stopwatch на моей машине на порядок хуже, чем на машине автора. В целом нужно согласиться с автором, что Stopwatch точнее (в моей случае на порядок), чем DateTime.Now.

Также следует иметь ввиду, что кроме низкого разрешения DateTime.Now работает медленнее DateTime.UtcNow, т.к. он пересчитывает часовые пояса. Соглашусь с советом Андрея Акиньшина, что в 99% случаев следует выбирать Stopwatch, а не DateTime. DateTime может потребоваться только в случае, если вам действительно нужно знать текущее время. Если реальное время не требуется, то используйте Stopwatch.