Я столкнулся с разницей в скорости, используя следующие две структуры:
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) Почему разработчики компилятора а) не сделали все структуры beforefieldinit
стандартными и б) не дали разработчикам возможность явно указать такое поведение? Конечно, это означает , если вы не можете, поскольку я не смог найти способ.
Edit:
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 секунды)