Производительность статического конструктора и почему мы не можем указать beforefieldinit

Я обнаружил разницу в скорости, используя следующие две структуры:

public struct NoStaticCtor
{
    private static int _myValue = 3;
    public static int GetMyValue() { return _myValue; }
}

public struct StaticCtor
{
    private static int _myValue;
    public static int GetMyValue() { return _myValue; }
    static StaticCtor()
    {
        _myValue = 3;
    }
}

class Program
{
    static void Main(string[] args)
    {
        long numTimes = 5000000000; // yup, 5 billion
        Stopwatch sw = new Stopwatch();
        sw.Start();
        for (long i = 0; i < numTimes; i++)
        {
            NoStaticCtor.GetMyValue();
        }
        sw.Stop();
        Console.WriteLine("No static ctor: {0}", sw.Elapsed);

        sw.Restart();
        for (long i = 0; i < numTimes; i++)
        {
            StaticCtor.GetMyValue();
        }
        sw.Stop();
        Console.WriteLine("with static ctor: {0}", sw.Elapsed);
    }
}

Что дает результат:

Release (x86), no debugger attached:
No static ctor: 00:00:05.1111786
with static ctor: 00:00:09.9502592

Release (x64), no debugger attached:
No static ctor: 00:00:03.2595979
with static ctor: 00:00:14.5922220

Компилятор создает статический конструктор для NoStaticCtor , который идентичен явному объявлению в StaticCtor . Я понимаю, что компилятор будет выдавать beforefieldinit только тогда, когда статический конструктор не определен явно.

Они производят почти идентичный код il, за исключением одного отличия, объявляя структуру с помощью beforefieldinit , в этом, как мне кажется, разница заключается в том, что он определяет, когда конструктор типа называется, хотя я не могу понять, почему такая разница. Предполагается, что он не вызывает конструктор типа на каждой итерации, поскольку конструктор типа может быть вызван только один раз. 1

Итак,

1) Почему разница во времени между структурой с beforefieldinit и структурой без? (Я предполагаю, что JITer делает что-то дополнительное в цикле for, однако я понятия не имею, как просмотреть вывод JITer, чтобы узнать, что.

2) Почему разработчики компилятора а) не сделали все структуры до fieldinit по умолчанию и б) не дали разработчикам возможность явно указать это поведение? Конечно, это - это , если вы не можете, поскольку я не смог найти способ.


Редактировать:

1 . Я изменил код , по сути, запустил каждый цикл второй раз, ожидая улучшения, но это было не так много:

No static ctor: 00:00:03.3342359
with static ctor: 00:00:14.6139917
No static ctor: 00:00:03.2229995
with static ctor: 00:00:12.9524860
Press any key to continue . . .

Я сделал это, потому что я подумал, может быть , однако маловероятно, что JITer фактически вызывал конструктор типа на каждой итерации. Мне кажется, что JITer будет знать, что конструктор типа уже был вызван, и не будет выдавать код для этого при компиляции второго цикла.

В дополнение к ответу Мотти: Этот код дает лучшие результаты, из-за разницы в JITing, JITing DoSecondLoop не генерирует статическую проверку ctor , поскольку он обнаружил, что это было сделано ранее в DoFirstLoop , в результате чего каждый цикл выполнялся с одинаковой скоростью. (~ 3 секунды)

7
задан Motti Shaked 16 November 2011 в 20:49
поделиться