gpt4 book ai didi

c# - 条件运算符慢吗?

转载 作者:IT王子 更新时间:2023-10-29 04:21:51 26 4
gpt4 key购买 nike

我正在查看一些代码,每个代码都有一个巨大的 switch 语句和一个 if-else 语句,并立即感受到了优化的冲动。作为一名优秀的开发人员,我总是应该这样做,我着手了解一些困难的时间事实,并从三个变体开始:

  1. 原始代码如下所示:

    public static bool SwitchIfElse(Key inKey, out char key, bool shift)
    {
    switch (inKey)
    {
    case Key.A: if (shift) { key = 'A'; } else { key = 'a'; } return true;
    case Key.B: if (shift) { key = 'B'; } else { key = 'b'; } return true;
    case Key.C: if (shift) { key = 'C'; } else { key = 'c'; } return true;
    ...
    case Key.Y: if (shift) { key = 'Y'; } else { key = 'y'; } return true;
    case Key.Z: if (shift) { key = 'Z'; } else { key = 'z'; } return true;
    ...
    //some more cases with special keys...
    }
    key = (char)0;
    return false;
    }
  2. 转换为使用条件运算符的第二个变体:

    public static bool SwitchConditionalOperator(Key inKey, out char key, bool shift)
    {
    switch (inKey)
    {
    case Key.A: key = shift ? 'A' : 'a'; return true;
    case Key.B: key = shift ? 'B' : 'b'; return true;
    case Key.C: key = shift ? 'C' : 'c'; return true;
    ...
    case Key.Y: key = shift ? 'Y' : 'y'; return true;
    case Key.Z: key = shift ? 'Z' : 'z'; return true;
    ...
    //some more cases with special keys...
    }
    key = (char)0;
    return false;
    }
  3. 使用预填充键/字符对的字典的扭曲:

    public static bool DictionaryLookup(Key inKey, out char key, bool shift)
    {
    key = '\0';
    if (shift)
    return _upperKeys.TryGetValue(inKey, out key);
    else
    return _lowerKeys.TryGetValue(inKey, out key);
    }

注意:两个 switch 语句具有完全相同的大小写,并且字典具有相同数量的字符。

我原以为 1) 和 2) 在性能上有些相似,而 3) 会稍微慢一些。

对于每个方法运行两次 10.000.000 次迭代进行预热然后计时,令我惊讶的是我得到以下结果:

  1. 每次调用 0.0000166 毫秒
  2. 每次调用 0.0000779 毫秒
  3. 每次调用 0.0000413 毫秒

这怎么可能?条件运算符比 if-else 语句慢四倍,​​比字典查找慢近两倍。我是否遗漏了一些重要的东西,或者条件运算符本身就很慢?

更新 1: 关于我的测试工具的几句话。我在 Visual Studio 2010 中的 Release 编译的 .Net 3.5 项目下为上述每个变体运行以下(伪)代码。打开代码优化并关闭 DEBUG/TRACE 常量。在进行定时运行之前,我运行一次测量方法进行热身。 run 方法执行该方法进行大量迭代,同时将 shift 设置为 true 和 false,并使用一组选择的输入键:

Run(method);
var stopwatch = Stopwatch.StartNew();
Run(method);
stopwatch.Stop();
var measure = stopwatch.ElapsedMilliseconds / iterations;

Run 方法如下所示:

for (int i = 0; i < iterations / 4; i++)
{
method(Key.Space, key, true);
method(Key.A, key, true);
method(Key.Space, key, false);
method(Key.A, key, false);
}

更新 2: 进一步挖掘,我查看了为 1) 和 2) 生成的 IL,发现主要开关结构与我预期的相同,但外壳略有不同.这是我正在查看的 IL:

1)if/else语句:

L_0167: ldarg.2 
L_0168: brfalse.s L_0170

L_016a: ldarg.1
L_016b: ldc.i4.s 0x42
L_016d: stind.i2
L_016e: br.s L_0174

L_0170: ldarg.1
L_0171: ldc.i4.s 0x62
L_0173: stind.i2

L_0174: ldc.i4.1
L_0175: ret

2) 条件运算符:

L_0165: ldarg.1 
L_0166: ldarg.2
L_0167: brtrue.s L_016d

L_0169: ldc.i4.s 0x62
L_016b: br.s L_016f

L_016d: ldc.i4.s 0x42
L_016f: stind.i2

L_0170: ldc.i4.1
L_0171: ret

一些观察:

  • 条件运算符在 shift 等于 true 时分支,而 if/else 在 shift 为 false 时分支。
  • 虽然 1) 实际上编译成比 2) 多几条指令,但当 shift 为 true 或 false 时执行的指令数对两者来说是相等的。
  • 1) 的指令顺序是始终只占用一个栈槽,而 2) 总是加载两个。

这些观察结果是否暗示条件运算符的执行速度会变慢?还有其他副作用吗?

最佳答案

很奇怪,也许 .NET 优化在您的案例中适得其反:

The author disassembled several versions of ternary expressions and found that they are identical to if-statements, with one small difference. The ternary statement sometimes produces code that tests the opposite condition that you would expect, as in it tests that the subexpression is false instead of testing if it is true. This reorders some of the instructions and can occasionally boost performance.

http://dotnetperls.com/ternary

您可能会考虑枚举值上的 ToString(对于非特殊情况):

string keyValue = inKey.ToString();
return shift ? keyValue : keyValue.ToLower();

编辑:
我已经将 if-else 方法与三元运算符进行了比较,并且在 1000000 个周期中,三元运算符始终至少与 if-else 方法一样快(有时快几毫秒,这支持上面的文本)。我认为您在测量所用时间时犯了某种错误。

关于c# - 条件运算符慢吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2259741/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com