C# 编译器会优化布尔赋值吗?
这就是我想做的:C# 编译器会优化布尔赋值吗?,c#,compiler-optimization,C#,Compiler Optimization,这就是我想做的: if(ABoolean || (BBoolean && CBoolean)) { SomeButton.Enabled = true; AnotherButton.Enabled = true; } else { SomeButton.Enabled = false; AnotherButton.Enabled = false; } 我可以切换到: SomeButton.Enabled = (ABoolean || (BBoo
if(ABoolean || (BBoolean && CBoolean))
{
SomeButton.Enabled = true;
AnotherButton.Enabled = true;
}
else
{
SomeButton.Enabled = false;
AnotherButton.Enabled = false;
}
我可以切换到:
SomeButton.Enabled = (ABoolean || (BBoolean && CBoolean));
AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean));
获取更简洁的代码。我的问题是,编译器是否优化赋值,使其看到布尔表达式是相同的,并为第二个按钮赋值,还是每次都计算值
注意:我知道这是一个很小的例子,加速/减速将是微不足道的,但它将有助于我更好地理解编译器优化
编辑:以下是我认为第二个选项可能会优化的原因:
class Program
{
static bool ABoolean = true, BBoolean = true, CBoolean = false;
static bool AEnable, BEnable;
static void Main(string[] args)
{
Stopwatch sw = new Stopwatch();
sw.Start();
for (int i = 0; i < 1000000000; i++)
{
Operation1();
}
sw.Stop();
Console.WriteLine(sw.ElapsedMilliseconds);
Stopwatch sw1 = new Stopwatch();
sw1.Start();
for (int i = 0; i < 1000000000; i++)
{
Operation2();
}
sw1.Stop();
Console.WriteLine(sw1.ElapsedMilliseconds);
Console.Read();
}
static void Operation1()
{
if (ABoolean || (BBoolean && CBoolean))
{
AEnable = true;
BEnable = true;
}
else
{
AEnable = false;
BEnable = false;
}
}
static void Operation2()
{
AEnable = (ABoolean || (BBoolean && CBoolean));
BEnable = (ABoolean || (BBoolean && CBoolean));
}
}
类程序
{
静态bool-ABoolean=true,BBoolean=true,CBoolean=false;
静态bool AEnable,BEnable;
静态void Main(字符串[]参数)
{
秒表sw=新秒表();
sw.Start();
对于(int i=0;i<100000000;i++)
{
操作1();
}
sw.Stop();
控制台写入线(软件延迟毫秒);
秒表sw1=新秒表();
sw1.Start();
对于(int i=0;i<100000000;i++)
{
操作2();
}
sw1.Stop();
Console.WriteLine(sw1.ElapsedMilliseconds);
Console.Read();
}
静态无效操作1()
{
if(ABoolean | |(BBoolean&CBoolean))
{
AEnable=正确;
可弯曲=正确;
}
其他的
{
AEnable=false;
可弯曲=错误;
}
}
静态无效操作2()
{
AEnable=(ABoolean | |(BBoolean&CBoolean));
BEnable=(ABoolean | |(BBoolean和CBoolean));
}
}
这导致在10亿次操作中产生约8-9秒的差异(第二个选项运行得更快)。然而,当我在中添加更多的“Enable”布尔值时,第二个操作变得更慢
我的问题是,编译器是否优化赋值,使其看到布尔表达式是相同的,并为第二个按钮赋值,还是每次都计算值
它将每次计算该值
如果这是一个多线程应用程序呢。其他线程可能会更改它
如果它们不是常量变量,则可以更改它们
为了优化您可以做的事情
SomeButton.Enabled = AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean));
在这种情况下,它将计算一次,并首先将值分配给另一个按钮,然后再分配给另一个按钮。记住它在赋值中是从右向左的。不,我不希望编译器优化它。JIT可能会对此进行优化(因为它有更多的信息),但我不希望C#编译器会这样做
编译器如何知道SomeButton.Enabled
是否会产生一些副作用,从而改变ABoolean
、BBoolean
或CBoolean
的值
编辑:验证此。。。让我们给C#编译器最大的机会:
编译时使用:
csc /o+ /debug- Test.cs
通过ILDASM为Foo
编码:
.method private hidebysig static void Foo(bool x,
bool y,
bool z) cil managed
{
// Code size 37 (0x25)
.maxstack 8
IL_0000: ldarg.0
IL_0001: brtrue.s IL_000c
IL_0003: ldarg.1
IL_0004: brfalse.s IL_0009
IL_0006: ldarg.2
IL_0007: br.s IL_000d
IL_0009: ldc.i4.0
IL_000a: br.s IL_000d
IL_000c: ldc.i4.1
IL_000d: call void Test::set_A(bool)
IL_0012: ldarg.0
IL_0013: brtrue.s IL_001e
IL_0015: ldarg.1
IL_0016: brfalse.s IL_001b
IL_0018: ldarg.2
IL_0019: br.s IL_001f
IL_001b: ldc.i4.0
IL_001c: br.s IL_001f
IL_001e: ldc.i4.1
IL_001f: call void Test::set_B(bool)
IL_0024: ret
} // end of method Test::Foo
如您所见,表达式在这两种情况下都会进行计算。不,根据我的经验,编译器不会对其进行优化,但是,您可以:
SomeButton.Enabled = AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean));
正确的。因为这是两个独立的语句,涉及的变量不是常量。因此编译器不能在这里假设任何东西。变量可能在这两个语句之间发生了变化,特别是当您的应用程序是多线程的时候。现在您只需要从其他人的答案中获取细节。真是好笑。但我不确定你发布的内容是否真的是优化。布尔运算速度非常快。我认为引用属性的
get
访问器通常与调用内联方法具有相同的开销。因此,这很容易比原始代码慢。虽然我们谈论的是纳秒,但仍然是。@SteveWortham:是的,我承认我复制了它。但是不是从某人的答案而是从我的大脑。实际上,get
访问器不会被引用,因为赋值的返回值就是被赋值的值。因此,布尔表达式将被计算一次,然后沿着链返回。如果分配链中有不同的类型,可能会产生一些微妙的影响,但这不是问题所在。@SteveCzetty-我运行了另一个测试,您是对的,从未调用get
访问器。但是我仍然不知道为什么速度会这么慢。顺便说一下:第三种方法是通过变量赋值:var enabled=(ABoolean | | |(BBoolean&&CBoolean))
,然后使用该变量设置.enabled
属性。感谢您的回答,我感到困惑,因为我实际上对这两个选项进行了计时,而第二个选项的结果要快得多。我假设这是由于if/else条款的开销造成的。因此,在第二种情况下,布尔运算的数量应该会出现一个无法返回的点,这会导致时间变慢,对吧?@NominSim:我不希望任何一种版本的结果都会显著加快。我怀疑你的诊断:)但是,真的,这对你整体来说可能有点重要吗?远远超过10亿次操作,差异约为8秒(~19对~11)…我认为重要是主观的,当我再添加5个布尔赋值时,第二个选项会变慢。绝对没有什么意义,我只是在解释我最初是如何得出结论的,即它可能会优化第二个版本。@NominSim:这听起来确实很有趣,但很容易破坏微优化测试;特别是,你可以很容易地发现一个版本是内联的,另一个版本不是,但在更大的方法中不会产生影响。我在我的OP中编辑了测试代码,我不确定秒表是否是计时这类事情的最佳方式……你介意看一下它,看看它是否可行吗
SomeButton.Enabled = AnotherButton.Enabled = (ABoolean || (BBoolean && CBoolean));