Есть несколько проблем с вашей методологией бенчмаркинга.
Во-первых, когда у вас есть два значения DateTime
, и вы сравниваете их по их TimeOfDay
свойствам ...
var startOne = DateTime.Now.TimeOfDay;
// Do some work
var endOne = DateTime.Now.TimeOfDay;
var resultOne = (endOne - startOne).Milliseconds;
... тогда вы рискуете получить отрицательную длительность, если тест охватит дневной переход (полночь).Учтите это ...
DateTime midnight = DateTime.Today;
DateTime fiveSecondsBeforeMidnight = midnight - TimeSpan.FromSeconds(5);
DateTime fiveSecondsAfterMidnight = midnight + TimeSpan.FromSeconds(5);
Console.WriteLine($"Difference between DateTime values: {fiveSecondsAfterMidnight - fiveSecondsBeforeMidnight}");
Console.WriteLine($"Difference between TimeOfDay values: {fiveSecondsAfterMidnight.TimeOfDay - fiveSecondsBeforeMidnight.TimeOfDay}");
... который печатает ...
Difference between DateTime values: 00:00:10
Difference between TimeOfDay values: -23:59:50
Вместо этого вы можете исправить эту ошибку и упростить свой код, сравнивая значения DateTime
напрямую...
var startOne = DateTime.Now;
// Do some work
var endOne = DateTime.Now;
var resultOne = (endOne - startOne).Milliseconds;
Это может быть улучшено, однако, с помощью Stopwatch
класса , который является более точным, чем сравнение значений DateTime
и специально разработанных для этой цели....
Stopwatch stopwatch = Stopwatch.StartNew();
// Do some work
TimeSpan resultOne = stopwatch.Elapsed;
stopwatch.Restart();
// Do some work
TimeSpan resultTwo = stopwatch.Elapsed;
Во-вторых, свойство TimeSpan.Milliseconds
возвращает только миллисекунды компонент значения TimeSpan
.Чтобы получить значение TimeSpan
в миллисекундах , необходимо свойство TotalMilliseconds
.Рассмотрим разницу здесь ...
TimeSpan value1 = TimeSpan.FromSeconds(1) + TimeSpan.FromMilliseconds(500);
TimeSpan value2 = TimeSpan.FromMilliseconds(900);
Console.WriteLine($" value1.Milliseconds: {value1.Milliseconds}");
Console.WriteLine($"value1.TotalMilliseconds: {value1.TotalMilliseconds}");
Console.WriteLine($" value2.Milliseconds: {value2.Milliseconds}");
Console.WriteLine($"value2.TotalMilliseconds: {value2.TotalMilliseconds}");
Console.WriteLine($"value1 is {(value1.Milliseconds < value2.Milliseconds ? "less" : "greater")} than value2 (by Milliseconds)");
Console.WriteLine($"value1 is {(value1.TotalMilliseconds < value2.TotalMilliseconds ? "less" : "greater")} than value2 (by TotalMilliseconds)");
... которая печатает ...
value1.Milliseconds: 500
value1.TotalMilliseconds: 1500
value2.Milliseconds: 900
value2.TotalMilliseconds: 900
value1 is less than value2 (by Milliseconds)
value1 is greater than value2 (by TotalMilliseconds)
Сравнение свойства Ticks
, как вы это сделали, было бы другим способом обойти этоили вы можете просто сохранить разницу во времени как TimeSpan
, не выбирая одно из его свойств, и позволить форматированию строк обрабатывать меньшие компоненты ...
TimeSpan resultOne = endOne - startOne;
TimeSpan resultTwo = endTwo - startTwo;
// ...
Console.WriteLine($"First option runs in: {resultOne:s\\.ffffff} seconds");
Console.WriteLine();
Console.WriteLine($"Second option runs in: {resultTwo:s\\.ffffff} seconds");
Наконец, я запустил ваш код и увиделрезультаты, которые вы сделали: первые прогоны отличны от нуля, а последующие прогоны равны нулю.Я думаю, что первые запуски занимают больше времени, потому что ваш код еще не был оптимизирован JIT.Даже эти «медленные» первые запуски занимают всего несколько миллисекунд, потому что ваш список состоит всего из тысячи элементов.Короткие тесты не дают значимых сравнений.
После внесения изменений, описанных выше, и увеличения размера List<>
, возвращаемого GetData()
до 10 миллионов элементов, каждый цикл занимает несколько секунд, при этом первыйОпция может быть на несколько миллисекунд быстрее при первом запуске и на 25-125 миллисекунд медленнее при последующих запусках.
Вместо того, чтобы переходить к собственному тестовому коду, вы можете использовать библиотеку, такую как BenchmarkDotNet .Он обрабатывает такие детали, как определение количества выполненных прогонов, «прогрев» вашего кода, чтобы убедиться, что он уже оптимизирован, и вычисление статистики для вас.