我碰到一个差排在速度使用以下两种结构:静态构造函数的性能和为什么我们不能指定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)为什么用beforefieldinit
的结构和没有一个之间的时间差? (我想JITer在for循环中做了一些额外的工作,但是,我不知道如何查看JITer的输出以查看内容。)
2)为什么编译器设计者a)没有使所有结构体beforefieldinit
是默认的,并且b)不给开发者明确指定该行为的能力?当然,这个是假设你不能,因为我一直没有找到办法。
编辑:
。 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产生更好的效果,因为在JIT编译不同之处,DoSecondLoop
的JIT编译不发出静态构造函数检查,因为它检测到它是在DoFirstLoop
以前那样,使每个循环执行以相同的速度。 (〜3秒)
这里需要大量的一些观点。您测量的开销是* 1纳秒*。是的,这是关于测试+跳转指令的作用。 –
@Hans我知道开销很小。我从来没有真正写过这样的代码在生产中使用。我目前正在进行“CLR工作如何”的工作,我一直在讨论不寻常的事情。我真的只是想知道为什么JITer根据编译器发出的属性来做出它所做的决定。我应该可以买一本书。 –