Running pusty dla pętli z dużą liczbą powtórzeń, Dostaję szalenie różne numery, jak długo to trwa do uruchomienia:Niepewność wydajności dla pętli w .NET x64: koligacja liczby parzystej?
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);
}
}
Powyższy będzie działać w około 200ms na moim komputerze, ale jeśli zwiększ go do 1000000001, a następnie tak długo trwa 4x! Następnie, jeśli zrobię to 1000000002, znowu będzie 200 ms!
Ten wydaje się być stanie się dla parzystej liczby iteracji. Jeśli przejdę na for (var i = 1; i < 1000000001
, (zanotuj od 1 zamiast 0), to 200 ms. Lub jeśli robię i <= 1000000001
(zauważ mniej niż lub równy), to 200 ms. Lub też (var i = 0; i < 2000000000; i += 2)
.
Ta opcja pojawia się tylko na x64, ale we wszystkich wersjach .NET do (co najmniej) 4.0. Pojawia się również tylko w trybie zwolnienia z odłączonym debuggerem.
UPDATE Myślałam, że jest to prawdopodobnie ze względu na jakiś mądry nieco przesunięcie w JIT, ale następujący wydaje się zaprzeczyć, że: jeśli robisz coś takiego stworzyć obiekt wewnątrz tej pętli, a następnie że trwa około 4x tak długo, zbyt:
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);
}
}
to trwa około 1 sekundę na moim komputerze, ale wtedy zwiększa się o 1 do 1000000001 trwa 4 sekundy. To dodatkowe 3000 ms, więc nie mogło to być spowodowane przesunięciem bitów, ponieważ oznaczałoby to również różnicę 3000 ms w pierwotnym problemie.
Być może rozwija dwie iteracje pętli, jeśli limit jest równy, a następnie zdaje sobie sprawę, że wynik pierwszej połowy iteracji nigdy nie jest używany i optymalizuje go. – CodesInChaos