gpt4 book ai didi

c# - 为什么只读字段检查不能在循环之外进行优化?

转载 作者:行者123 更新时间:2023-12-05 08:37:00 26 4
gpt4 key购买 nike

当我有一个只读变量时:

public readonly bool myVar = true;

然后用这样的代码检查它:

for(int i = 0; i != 10; i++)
{
if(myVar)
DoStuff();
else
DoOtherStuff();
}

查看发出的 IL,我可以看到在循环的每次迭代中都执行了检查。我希望上面的代码产生与此相同的 IL:

if (myVar)
{
for(int i = 0; i != 10; i++)
{
DoStuff();
}
}
else
{
for(int i = 0; i != 10; i++)
{
DoOtherStuff();
}
}

既然字段是只读的并且不能在迭代之间更改,那么为什么不在循环外部优化检查?

最佳答案

您提出的优化实际上是两个单独的更简单转换的组合。首先是将成员访问拉到循环之外。来自

for(int i = 0; i != 10; i++)
{
var localVar = this.memberVar;
if(localVar)
DoStuff();
else
DoOtherStuff();
}

var localVar = this.memberVar;
for(int i = 0; i != 10; i++)
{
if(localVar)
DoStuff();
else
DoOtherStuff();
}

第二个是将循环条件与 if 条件互换。来自

var localVar = this.memberVar;
for(int i = 0; i != 10; i++)
{
if(localVar)
DoStuff();
else
DoOtherStuff();
}

var localVar = this.memberVar;
if (localVar) {
for(int i = 0; i != 10; i++)
DoStuff();
}
else {
for(int i = 0; i != 10; i++)
DoOtherStuff();
}

第一个受readonly的影响。为此,编译器必须证明 memberVar 不能在循环内改变,并且 readonly 保证 this1 —— 即使这个循环可能在构造函数中调用,memberVar 的值可以在循环结束后在构造函数中更改,它不能在循环体中更改 -- DoStuff() 是不是当前对象的构造函数,DoOtherStuff() 也不是。反射不算在内,虽然可能可能使用反射来打破不变量,但不允许这样做。线程确实很重要,请参阅脚注。

第二个是一个简单的转换,但编译器更难做出决定,因为很难预测它是否真的会提高性能。自然你可以单独看一下,自己对代码做第一个转换,看看生成了什么代码。

也许更重要的考虑因素是,在 .NET 中,优化过程发生在 MSIL 和机器代码之间,而不是在将 C# 编译为 IL 期间。因此,您无法通过查看 MSIL 了解正在进行哪些优化!


1 或者是吗? .NET 内存模型比例如在 C++ 模型中,任何数据竞争都会很快导致未定义的行为,除非对象被定义为 volatile/atomic。如果此循环在从对象构造函数派生的工作线程中运行,并且在派生线程之后,构造函数继续(我将其称为“下半场”)更改 readonly 成员,会怎样?内存模型是否需要工作线程看到该更改?如果 DoStuff() 和构造函数的后半部分强制内存栅栏,例如访问其他 volatile 成员,或者获取锁怎么办?所以 readonly 只允许在单线程环境中进行优化

关于c# - 为什么只读字段检查不能在循环之外进行优化?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66912010/

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