編集
正しく使用Stopwatch
し、反復回数を 2 桁増やすと、次のようになります。
3 進数は 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<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;
}
}
例外は発生せず、コンソールへの出力は次のようになります。
3 進数は 107 ミリ秒かかりました
通常は230ミリ秒かかりました
2 つの論理関数の 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
}
CILTernary
は少し短いですが、どちらの関数も CIL を介した実行パスは 3 回のロード、1 回または 2 回のジャンプ、および 1 回のリターンを必要とするように思えます。Ternary
関数が 2 倍高速に見えるのはなぜですか。
実際には、どちらも非常に高速であり、実際には十分に高速であることは理解していますが、その不一致を理解したいと思います。