gpt4 book ai didi

c# - 静态构造函数性能以及为什么我们不能指定 beforefieldinit

转载 作者:太空狗 更新时间:2023-10-29 20:08:23 24 4
gpt4 key购买 nike

我发现使用以下两个结构在速度上存在差异:

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 的struct 和没有的有时间差? (我想 JITer 在 for 循环中做了一些额外的事情,但是,我不知道如何查看 JITer 的输出以查看什么。

2) 为什么编译器设计者 a) 没有让所有结构 beforefieldinit 成为默认结构并且 b) 没有让开发人员能够明确指定该行为?当然,这假设你做不到,因为我还没有找到办法。


编辑:

1I 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 会知道类型构造函数已经被调用,并且不会在编译第二个循环时发出代码来执行此操作。

除了莫蒂的回答: This code产生更好的结果,因为 JITing 的不同,DoSecondLoop 的 JITing 不发出静态 ctor 检查,因为它检测到它之前在 DoFirstLoop 中完成,导致每个循环以相同的速度执行。 (~3 秒)

最佳答案

第一次访问您的类型时,必须执行静态构造函数(无论是显式还是隐式生成)。

当 JIT 编译器将 IL 编译为 native 指令时,它会检查该类型的静态构造函数是否已执行,如果未执行,则发出 native 代码以检查(再次)静态构造函数是否已被执行,如果没有,则执行它。

已缓存 jitted 代码以供将来调用同一方法(这就是代码必须再次检查静态 ctor 是否已执行的原因)。

问题是,如果检查静态 ctor 的 jitted 代码处于循环中,则此测试将在每次迭代中发生。

当存在 beforefieldinit 时,允许 JIT 编译器优化代码,方法是在进入循环之前测试静态 ctor 调用。如果不存在,则不允许进行此优化。

C# 编译器会自动为我们决定何时发出此属性。目前(C# 4)仅当代码未显式定义静态构造函数时才会发出它。它背后的想法是,如果您自己定义了一个静态 ctor,那么时机对您来说可能更重要,并且 ststic ctor 不应该提前执行。这可能是正确的,也可能不是正确的,但您无法更改此行为。

这是我的在线 .NET 教程中详细解释此部分的链接:http://motti.me/c1L

顺便说一句,我不建议在结构上使用静态 ctors,因为信不信由你,它们不能保证执行!这不是问题的一部分,所以我不会详细说明,但如果您有兴趣,请参阅此以获取更多详细信息:http://motti.me/c1I (我在视频中大约 2 点 30 分触摸到主题)。

希望对您有所帮助!

关于c# - 静态构造函数性能以及为什么我们不能指定 beforefieldinit,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8156458/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com