#c#
#c#
Вопрос:
Я пытаюсь что-то сравнить.
У меня есть цикл, подобный
for (int i = 1; i <= 1000; i )
{
Thing thing = createThing(i);
DateTime startTime = DateTime.Now;
thing.ComputationallyExpensiveOp();
TimeSpan elapsed = DateTime.Now - startTime;
Console.WriteLine(String.Format("i = " i "ttime = " elapsed.TotalMilliseconds);
}
Похоже, что первая итерация, i = 1
, занимает значительное количество времени дольше, чем следовало бы (на несколько порядков), исходя из того, сколько времени требуется для завершения остальных.
Вторая итерация также часто кажется слишком длинной, хотя и менее очевидной.
Я чувствую, что это потому, что цикл вызывает кэширование большого количества значений, которые не были настроены на первой итерации.
Есть ли способ сделать первую итерацию i = 1
такой же «быстрой» (с точки зрения накладных расходов), как и остальные, чтобы я действительно только рассчитывал время (как можно лучше) thing.ComputationallyExpensiveOp()
.
На данный момент очевидно, что первая итерация не является точным отражением thing.ComputationallyExpensiveOp()
.
Я уже пытался переместить инициализацию «прогрева» над циклом, но это не сработало.
Thing thing = createThing(1);
thing.ComputationallyExpensiveOp();
for (int i = 1; i <= 1000; i )
{
thing = createThing(i);
DateTime startTime = DateTime.Now;
thing.ComputationallyExpensiveOp();
TimeSpan elapsed = DateTime.Now - startTime;
Console.WriteLine(String.Format("i = " i "ttime = " elapsed.TotalMilliseconds);
}
Комментарии:
1. Какую «инициализацию прогрева» вы пробовали, но не сработало? Обычно вызов кода, который должен быть протестирован, работает
2. @harold Я отредактировал, чтобы показать. Я собираюсь протестировать копирование также
Conole.WriteLine
и таймингов и т.д.3. Вероятно, просто время циклов x и выведите медиану или среднее значение партии. Поскольку звучит так, как будто вы не можете контролировать кэширование, происходящее в createThing()
4. Как мы можем разумно ответить на это, не зная, что происходит в CreateThing и ComputationallyExpensiveOp? Какое кэширование присутствует в этих двух методах?
5. Я скопировал все тело цикла над циклом, и, похоже, это «исправлено». Ofc Я не могу быть уверен, но цифры выглядят намного больше, чем ожидалось сейчас.
Ответ №1:
Я использую такие for
циклы десятилетиями. И я никогда не сталкивался с тем, что такой for
цикл был причиной задержки во время первой итерации.
Я ничего не знаю о вашей Thing
реализации, но я совершенно уверен, что причина вашей задержки кроется именно в этом. Не в цикле.
Комментарии:
1. Вероятно, это ни то, ни другое, но просто в C # первый вызов любого метода происходит медленно, потому что код еще не был JIT-скомпилирован (поэтому время для его JIT-компиляции включено в тест, если вы вызываете холодный код)
2. Верно, но если
ComputationallyExpensiveOp
в OP на самом деле не так дорого с точки зрения вычислений, компиляция JIT не объясняет «на несколько порядков» более длительное выполнение первой итерации в этом цикле… Я понимаю, что компиляция JIT сопряжена с накладными расходами, но, как я уже сказал, я никогда не сталкивался с такой задержкой, вызванной моим компилятором / средой за всю мою карьеру. Это всегда в первую очередь было связано с деталями реализации разработанной мной логики.
Ответ №2:
Копирование всего тела цикла снаружи «исправило» это для меня
Thing thing = createThing(1);
DateTime startTime = DateTime.Now;
thing.ComputationallyExpensiveOp();
TimeSpan elapsed = DateTime.Now - startTime;
Console.WriteLine(String.Format("i = " 1 "ttime = " elapsed.TotalMilliseconds);
for (int i = 1; i <= 1000; i )
{
thing = createThing(i);
startTime = DateTime.Now;
thing.ComputationallyExpensiveOp();
elapsed = DateTime.Now - startTime;
Console.WriteLine(String.Format("i = " i "ttime = " elapsed.TotalMilliseconds);
}
Я не совсем уверен в причине, но теперь время выполнения первой итерации больше похоже на ожидаемое.
Комментарии:
1. Я рад, что это решение сработало для вас. Однако это остается странной проблемой. Объявление трех переменных вне
for
цикла не должно приводить к заметному увеличению производительности, особенно еслиthing.ComputationallyExpensiveOp()
вызов будет потреблять большую часть общей вычислительной мощности вашей логики. Если у вас будет такая возможность, я бы посоветовал вам продолжить изучение этой проблемы. Если истинное происхождение проблемы остается нераскрытым, вы можете столкнуться со «спонтанным» ее повторным появлением рано или поздно. И к тому времени это может быть сложнее определить и решить.2. @BartHofland да, я тоже подумал, что это странно, к счастью, это не часть чего-либо, что я буду использовать повторно в будущем, но я мог бы исследовать это снова через несколько дней, чтобы обновить этот пост SO