нечетность производительности цикла в .NET x64: сходство с четными числами итераций?
Запустив пустой цикл for с большим количеством итераций, я получаю дико отличающиеся числа от того, сколько времени потребуется для запуска:
public static class Program
{
static void Main()
{
var sw = new Stopwatch();
sw.Start();
for (var i = 0; i < 1000000000; ++i)
{
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
Вышеуказанное будет работать на моей машине примерно через 200 мс, но если я увеличу его до 1000000001, то потребуется4x как долго! Тогда, если я сделаю это 1000000002, то снова снизится до 200мс!
Этоткажется произойти за четное количество итераций. Если я пойдуfor (var i = 1; i < 1000000001
, (обратите внимание, начиная с 1 вместо 0), то это 200 мс. Или если я сделаюi <= 1000000001
(обратите внимание, меньше, чемили равно) тогда это 200мс. Или же(var i = 0; i < 2000000000; i += 2)
также.
Это, кажется, только на x64, но на всех версиях .NET до (по крайней мере) 4.0. Также он появляется только в режиме релиза с отключенным отладчиком.
ОБНОВИТЬ Я думал, что это, вероятно, из-за некоторого умного сдвига битов в jit, но следующее, кажется, опровергает это: если вы делаете что-то вроде создания объекта внутри этого цикла, тоэто занимает около 4х раз:
public static class Program
{
static void Main()
{
var sw = new Stopwatch();
sw.Start();
object o = null;
for (var i = 0; i < 1000000000; i++)
{
o = new object();
}
sw.Stop();
Console.WriteLine(o); // use o so the compiler won't optimize it out
Console.WriteLine(sw.ElapsedMilliseconds);
}
}
На моей машине это занимает около 1 секунды, но затем увеличивается на 1 до 1000000001.4 секунды, Это дополнительные 3000 мс, так что на самом деле это не может быть связано со смещением битов, поскольку это также показало бы разницу в 3000 мс в исходной задаче.