【问题标题】:C++: Performance of Switch Statement vs Lookup tablesC++:Switch 语句与查找表的性能
【发布时间】:2018-01-24 06:00:01
【问题描述】:

我尝试比较switch 语句和查找表的性能,如下所示。

这是使用switch语句的代码

#include <stdio.h>

int main()
{
    int n = 3;

    for (long i = 0; i < 10000000; ++i) {  
        switch (n) {
        case 0:
            printf("Alpha");
            break;
        case 1:
            printf("Beta");
            break;
        case 2:
            printf("Gamma");
            break;
        case 3:
            printf("Delta");
            break;
        default:
            break;
        }
    }

    return 0;
}

下面是使用查找表的代码:

#include <stdio.h>

static char const * const Greek[4] = {
  "Alpha",
  "Beta",
  "Gamma",
  "Delta"
};

int main()
{
    int n = 3;

    for (long i = 0; i < 10000000; ++i) {  
        if (n >= 0 && n < 4) {
            printf(Greek[n]);
        }
    }

    return 0;
}

我在 ubuntu 14.04 上运行两个程序,gcc 版本 4.8.4,使用 perf 版本 4.4.13 来分析性能。结果:

  • Switch 语句:6.764077822 秒
  • 查找表:6.665140483 秒

我不知道为什么 Switch 语句的运行速度比查找表慢。正如我所知,使用跳转表的 Switch 语句,我认为它应该比我的程序中的查找表运行得更快(它有额外的 if 语句)。

【问题讨论】:

  • 您的时间包括调用printf,这可能会导致结果不准确。
  • 你应该看看生成的汇编代码。
  • 如果你开启了优化,switchif 都将被一个好的优化编译器优化掉。
  • 请注意,如果您用-O3 编译它们是相同的,编译器会识别n=3 并删除与其他情况相关的所有内容(包括ifswitch)。
  • 使用godbolt.org 编译器资源管理器,它会立即显示生成的汇编代码。您可以选择不同的编译器,并且可以指定所有编译标志。还要将n = 3 更改为n = rand(),这样优化器就不会优化掉大部分代码。

标签: c++ c performance switch-statement lookup-tables


【解决方案1】:

如果您使用优化进行编译,则您的代码没有开关,也没有查找表。我只是一个 for 循环,它使用相同的固定字符串多次调用 printf()。事实上,任何最低限度合理的编译器都会检测到n = 3 从未更改并对其进行优化。也许您可以在循环内添加n = rand() % 4;

另一方面,如果您不进行优化编译,那么计时是没有意义的。

关于您的问题,我希望查找表比 switch 语句更快,因为 switch 语句将完全破坏分支预测,而 if 将没问题,始终为真。

【讨论】:

  • 我使用 gcc 版本 4.8.4 和默认选项。我会尝试不使用优化编译器。
  • @tuanpm 不!正如我所说,计时未优化的代码是没有意义的!它什么都不会告诉你。
【解决方案2】:

您的基准完全不足以衡量switch/lookup-table 的性能:几乎所有时间都花在了printf() 调用中。如果switch/lookup-table 的差异有任何影响,由于总运行时间较大,它与测量噪声相形见绌。


供参考:我预计在一个热的、紧密的循环中查找表只需大约 10 个时钟周期。在 2 GHz CPU 上,所有 10000000 次迭代只需 0.05 秒(粗略估计,很容易出错两倍,但这不会影响整体评估)。占总运行时间的 1%!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-28
    • 2018-05-05
    • 1970-01-01
    • 2021-07-24
    • 2011-11-27
    • 1970-01-01
    相关资源
    最近更新 更多