Blo*_*ust 21 c# optimization conditional if-statement boolean
非常简单的问题.我知道这可能是一个很小的优化,但最终你会使用足够的if语句来解决它.
编辑:谢谢那些提供答案的人.
对于那些觉得需要打击我的人,要知道好奇心和对知识的渴望并不能转化为愚蠢.
非常感谢所有提出建设性批评的人.直到现在我才知道if(var)的能力.我很确定我现在会用它.;)
Eri*_*ert 69
首先:回答性能问题的唯一方法是测量它.亲自尝试,你会发现.
至于编译器的作用:我提醒你"if"只是一个条件goto.当你有
if (x)
Y();
else
Z();
Q();
Run Code Online (Sandbox Code Playgroud)
编译器将其生成为:
evaluate x
branch to LABEL1 if result was false
call Y
branch to LABEL2
LABEL1:
call Z
LABEL2:
call Q
Run Code Online (Sandbox Code Playgroud)
要么
evaluate !x
branch to LABEL1 if result was true
Run Code Online (Sandbox Code Playgroud)
取决于是否更容易生成代码以引出"x"恰好是"正常"或"反转"结果.例如,如果你有if (a<=b)它可能更容易生成它(if !(a>b)).或相反亦然; 这取决于正在编译的确切代码的细节.
无论如何,我怀疑你有更大的鱼要炸.如果您关心性能,请使用分析器并找到最慢的东西,然后解决它.当你可能在程序中的其他地方浪费整整毫秒时,毫无意义地担心纳秒优化.
Jon*_*nna 42
您是否知道在x86处理器上x ^= x,x比32位整数更有效率x = 0呢?这是真的,当然也有相同的结果.因此,任何人都可以x = 0在代码中看到,可以用代替它x ^= x并获得效率.
现在,你见过x ^= x很多代码吗?
你没有的原因不仅仅是因为效率增益很小,而是因为这正是编译器(如果编译为本机代码)或抖动(如果编译IL或类似代码)会产生的那种变化.反汇编一些x86代码,看到程序集等效的并不罕见x ^= x,虽然为此编译的代码几乎肯定有x = 0或者可能更复杂的代码,x = 4 >> 6或者x = 32 - y代码分析显示此时y总是包含的代码32,以及等等.
出于这个原因,即使x ^= x已知效率更高,但它在绝大多数情况下的唯一影响是使代码的可读性降低(唯一的例外x ^= y是在使用的算法中需要做的事情和我们碰巧做了一个案例,在这里x和y在这里相同,在这种情况下x ^= x会使该算法的使用更加清晰而x = 0隐藏它).
在99.999999%的案例中,同样适用于您的示例.在剩余的0.000001%的情况下,它应该存在但是在某些奇怪的运算符覆盖之间存在效率差异,并且编译器无法将其中一个解析为另一个.事实上,0.000001%是夸大案件,刚才提到因为我很确定如果我努力了,我可以写一些效率低于另一个的东西.通常人们并不努力这样做.
如果您在反射器中查看自己的代码,您可能会发现一些与您编写的代码看起来非常不同的情况.这样做的原因是,它是反向工程代码的IL,而不是你的代码本身,确实有一件事你会经常发现是类似的东西if(var == true)或者if(var != false)正在变成if(var)甚至到if(!var)与if和else块反转.
看得更深,你会发现即使是进一步的改变,也有不止一种方法可以让同一只猫皮肤光滑.特别是,查看switch语句转换为IL的方式很有意思; 有时候它变成了一堆if-else if语句的等价物,有时它变成了一个可以进行跳转的表的查找,这取决于在所讨论的情况下看起来更有效.
查看更深入,并在编译为本机代码时进行其他更改.
我不同意那些谈论"过早优化"的人只是因为你询问两种不同方法之间的性能差异,因为对这种差异的了解是一件好事,它只是过早地使用这种知识是不成熟的(通过定义).但是,即将被编译出来的变化既不是过早的,也不是优化,它只是一个零变化.
jms*_*era 18
它根本不会有任何区别.使用反射器你可以看到代码:
private static void testVar(bool var)
{
if (var == true)
{
Console.WriteLine("test");
}
if (var != false)
{
Console.WriteLine("test");
}
if (var)
{
Console.WriteLine("test");
}
}
Run Code Online (Sandbox Code Playgroud)
创建IL:
.method private hidebysig static void testVar(bool var) cil managed
{
.maxstack 8
L_0000: ldarg.0
L_0001: brfalse.s L_000d
L_0003: ldstr "test"
L_0008: call void [mscorlib]System.Console::WriteLine(string)
L_000d: ldarg.0
L_000e: brfalse.s L_001a
L_0010: ldstr "test"
L_0015: call void [mscorlib]System.Console::WriteLine(string)
L_001a: ldarg.0
L_001b: brfalse.s L_0027
L_001d: ldstr "test"
L_0022: call void [mscorlib]System.Console::WriteLine(string)
L_0027: ret
}
Run Code Online (Sandbox Code Playgroud)
因此编译器(在.Net 3.5中)将它们全部转换为ldarg.0,brfalse.s指令集.
Mic*_*tta 11
无论您在程序中使用多少次迭代,都不会产生任何可测量的差异.
(if (var)改为使用;您不需要比较的视觉混乱.)
EMP*_*EMP 11
它将使绝对零差异,因为编译器几乎肯定会将两个语句编译为相同的二进制代码.
(伪)程序集将是:
test reg1, reg2
br.true somewhere
; code for false case
somewhere:
; code for true case
Run Code Online (Sandbox Code Playgroud)
要么
test reg1, reg2
br.false somewhere
; code for true case
somewhere:
; code for false case
Run Code Online (Sandbox Code Playgroud)
编译器选择哪一个不取决于你是否写== true或!= false.相反,它是编译器根据真假案例代码的大小以及其他一些因素进行的优化.
顺便说一句,在Linux内核代码实际上并尝试使用这些分支,以优化LIKELY和UNLIKELY宏的if条件,所以我想这是可以手动控制.
通常有效的经验法则是"如果你知道它们做同样的事情,那么编译器也会知道".
如果编译器知道两个表单产生相同的结果,那么它将选择最快的一个.
因此,假设它们同样快,直到你的探查器告诉你.
始终优化以便于理解.就我而言,这是编程的基本规则.在 您知道需要这样做之前,您不应该进行微观优化,甚至根本不进行优化,以及您需要这样做的地方.这是一个非常罕见的情况,挤出每一盎司的性能比可维护性更重要,甚至更难以让你知道在最初编写代码时优化的地方.
此外,这样的事情会以任何体面的语言自动优化.
tl;博士不要打扰
| 归档时间: |
|
| 查看次数: |
9809 次 |
| 最近记录: |