Я обнаружил разницу в скорости, используя следующие две структуры:
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 секунды)