修改
如果我正确地使用Stopwatch
并且迭代次数增加了两个数量级,我得到了
三元花了22404ms
正常需要21403ms
这些结果更接近我的期望,让我觉得世界上的一切都是正确的(如果不是我的代码。)
三元/条件运算符实际上稍慢。
继续this question,我已部分answered。
我在x64 Release Mode中编译此控制台应用程序,并启用了优化,并在没有附加调试器的情况下从命令行运行它。
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<bool, int, int> 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;
}
}
我没有任何异常,输出到控制台的东西很接近,
三元花了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
函数的速度似乎快两倍。
我认为,在实践中,它们都非常快,而且确实足够,但是,我想了解这种差异。
答案 0 :(得分:8)
两者的时间差不多。
您的结果已关闭,因为您没有正确使用Stopwatch
。 “正常”的测量包括两个的操作时间。
如果你改变了第二个
stopwatch.Start();
到
stopwatch.Restart();
然后你会得到正确的结果。
顺便说一下,为了获得更公平的比较,你应该执行
return (condition ? value + 2 : value + 1);
而不是
return value + (condition ? 2 : 1);
因此它完全等同于其他功能。否则,您不仅要测量 条件运算符。