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)为什么struct与beforefieldinit和没有?之间的时差? (我想JITer在for循环中做了一些额外的事情,但是,我不知道如何查看JITer的输出以查看内容.
2)为什么编译器设计者a)不能使beforefield之前的所有结构都是默认的,而b)不能让开发人员明确指定该行为?当然,这是假设你不能,因为我还没有找到办法.
编辑:
1. I modified the code,基本上第二次运行每个循环,期待一个改进,但它并不多:
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会知道类型构造函数已被调用,并且在编译第二个循环时不会发出代码来执行此操作.
除了Motti的回答:
This code产生更好的结果,因为JITing的差异,DoSecondLoop的JITing不会发出静态ctor检查,因为它检测到它先前在DoFirstLoop中完成,导致每个循环以相同的速度执行. (~3秒)
解决方法
当JIT编译器将IL编译为本机指令时,它会检查该类型的静态ctor是否已执行,如果不是,则发出本机代码(再次)检查静态ctor是否已执行,如果不执行,则执行它.
缓存的代码被缓存以供将来调用相同的方法(这就是为什么代码必须再次检查静态ctor是否被执行).
问题是,如果检查静态ctor的jitted代码处于循环中,则此测试将在每次迭代中进行.
当beforefieldinit存在时,允许JIT编译器通过在进入循环之前测试静态ctor调用来优化代码.如果不存在,则不允许进行此优化.
C#编译器会自动决定何时发出此属性.它目前(C#4)只有在代码没有明确定义静态构造函数时才会发出它.它背后的想法是,如果你自己定义一个静态的ctor,时间可能对你来说更重要,并且ststic ctor不应该提前执行.这可能是也可能不是,但你无法改变这种行为.
这是我在线.NET教程部分的链接,详细解释了这一点:http://motti.me/c1L
顺便说一句,我不建议在结构上使用静态ctors,因为信不信由你,它们不能保证执行!这不是问题的一部分,所以我不会详细说明,但如果你感兴趣的话,请看更多细节:http://motti.me/c1I(我在2:30左右触摸视频主题).
我希望这有帮助!