为什么条件(三元)运算符看起来明显更快?

编辑

如果我正确使用Stopwatch ,并且迭代次数增加了两个数量级

三元花了22404ms

正常需要21403ms

这些结果更接近我的预期,让我觉得这个世界是对的(如果不是我的代码。)

三元/条件运算符实际上稍慢。


继这个问题之后 ,我已经部分回答了 这个问题 。

我在x64发布模式下编译此控制台应用程序,并进行优化,并在没有附加调试器的情况下从命令行运行它。

 using System; using System.Diagnostics; class Program { static void Main() { var stopwatch = new Stopwatch(); var ternary = Looper(10, Ternary); var normal = Looper(10, Normal); if (ternary != normal) { throw new Exception(); } stopwatch.Start(); ternary = Looper(10000000, Ternary); stopWatch.Stop(); Console.WriteLine( "Ternary took {0}ms", stopwatch.ElapsedMilliseconds); stopwatch.Start(); normal = Looper(10000000, Normal); stopWatch.Stop(); Console.WriteLine( "Normal took {0}ms", stopwatch.ElapsedMilliseconds); if (ternary != normal) { throw new Exception(); } Console.ReadKey(); } static int Looper(int iterations, Func operation) { var result = 0; for (int i = 0; i < iterations; i++) { var condition = result % 11 == 4; var value = ((i * 11) / 3) % 5; result = operation(condition, value); } return result; } static int Ternary(bool condition, in value) { return value + (condition ? 2 : 1); } static int Normal(int iterations) { if (condition) { return = 2 + value; } return = 1 + value; } } 

我没有任何exception,输出到控制台是接近,

三元花了107毫秒

正常需要230毫秒

当我为两个逻辑函数分解CIL时,我得到了这个,

 ... Ternary ... { : ldarg.1 // push second arg : ldarg.0 // push first arg : brtrue.s T // if first arg is true jump to T : ldc.i4.1 // push int32(1) : br.s F // jump to F T: ldc.i4.2 // push int32(2) F: add // add either 1 or 2 to second arg : ret // return result } ... Normal ... { : ldarg.0 // push first arg : brfalse.s F // if first arg is false jump to F : ldc.i4.2 // push int32(2) : ldarg.1 // push second arg : add // add second arg to 2 : ret // return result F: ldc.i4.1 // push int32(1) : ldarg.1 // push second arg : add // add second arg to 1 : ret // return result } 

虽然Ternary CIL稍短,但在我看来,通过CIL执行任一函数的执行路径需要3次加载和1或2次跳转以及返回。 为什么Ternary函数看起来快两倍。

我认为,在实践中,它们都非常快,而且确实足够,但是,我想了解这种差异。

两者的时间差不多完全相同。

您的结果已关闭,因为您没有正确使用Stopwatch 。 “正常”的测量包括两个弯曲者所花费的时间。

如果你改变第二个

 stopwatch.Start(); 

 stopwatch.Restart(); 

然后你会得到正确的结果。


顺便说一句,为了获得更公平的比较,你应该执行

  return (condition ? value + 2 : value + 1); 

代替

  return value + (condition ? 2 : 1); 

这样它就完全等同于其他function。 否则,您不仅要测量条件运算符。