if语句、switch语句和函数指针的速度比较

5
我正在构建一个小型解释器,所以我想测试一下if、switch和函数指针之间的速度比较。使用19个else if的if语句比有20个case的switch稍微快一些,而函数指针(一个包含20个函数指针的数组)比前两者要慢得多... 我原本期望结果完全相反,有人能解释一下吗?

4
这里有一个问题吗?至少,您需要展示一些代码。如果仅有大约20个案例,您不可能测量出这三者之间的任何差异... - user123456
我可以确认你的结果。我也打赌指针数组是最快的。这只是在进行任何优化之前使用分析器的另一个原因。 - vava
你必须在计时测试中包含“指针数组”的运行时初始化。此外,编译器可能会优化掉间接函数调用,因为你将所有内容都放在同一个翻译单元中。你无法通过20个简单的测试用例来说服我你能够测量出它们之间的差异! - user123456
哎呀,这段代码太大了,有20个情况,20个if语句,还有更多... - user276634
你要检查什么样的值? - EvilTeach
显示剩余2条评论
1个回答

12

对于现代处理器来说,这在很大程度上取决于分支预测。尽管一个switch语句可以被实现为一个跳转表,在执行代码的任何分支上花费相同的时间,但它通常是非常不可预测的 - 真的; 分支预测器经常不能很好地预测哪个分支会被选择,这意味着存在非常大的流水线气泡(通常约为15个浪费周期)。

if语句可能会进行更多的比较,但其中大部分分支几乎每次都以相同的方式被选中,因此分支预测器可以更准确地预测它们的结果。

指向函数的指针也可能非常不可预测。更糟糕的是,直到最近,大多数处理器几乎根本没有尝试过。只有最近的BTB(分支目标缓冲区)实现足够强大,才能真正尝试通过指针来预测分支的目标。在旧的处理器上,指向函数的指针在速度比较中通常表现得很差。


你怎么把函数指针放到同一个类中,与分支完全无关呢?你仍然需要一些逻辑分支来分配函数指针... - user123456
1
一个典型的情况是函数指针数组,其中你原本在 switch 语句中使用的值被用作索引来访问该数组。 - Jerry Coffin
谢谢,Jerry :) 那么,你是说测试这个没有意义吗?我的第一个解释器使用了 ifs,第二个是用 C# 的字符串 ifs 实现的,第三个又回到了 C++,但是使用了函数指针。我没有看到像指针那样的改进,但语言不同,所以我不确定。 - user276634
请注意,具有(n) case…break 基本块的switch可以转换为可通过不超过log(n)个分支到达的(n)个基本块,而一系列if…else if最多需要(n)个分支,除非编译器非常聪明。 OP指出switchelse if快。@STing:函数调用是一类分支指令,您可以声明一个静态函数指针数组(在OP的情况下很可能)来分配它们而无需分支,甚至可能根本不调用用户空间代码。 - Potatoswatter
@STing:在处理器内部,下一条指令是通过增加指令指针来找到的,除非当前指令是分支指令。如果忽略无条件分支,你可以使用“无分支”的代码编写一个无限循环。无论是否有条件,分支都会跳转到基本块的开头。在PowerPC中,一些无条件分支(包括所有间接函数调用)实际上被编码为带有“条件始终为真”的条件分支! - Potatoswatter
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接