switch语句大约有30 case
s,由0到30的被禁止的无符号整数组成。
我可以做以下事情:
class myType
{
FunctionEnum func;
string argv[123];
int someOtherValue;
};
// In another file:
myType current;
// Iterate through a vector containing lots of myTypes
// ... for ( i=0; i < myVecSize; i ++ )
switch ( current.func )
{
case 1:
//...
break;
// ........
case 30:
// blah
break;
}
每次都用func
切换到开关。关于切换的好处还在于我的代码比30个函数更有条理。
或者我可以做到(不太确定):
class myType
{
myReturnType (*func)(int all, int of, int my, int args );
string argv[123];
int someOtherValue;
};
然后我有30个不同的函数,在开始时,指向其中一个的指针被分配给myType。
每秒通话次数:约1000万。 我不能只测试它 - 这需要我重写整个事情。目前正在使用开关。
我正在构建一个我想要比Python更快的解释器。 Ruby - 每个时钟周期都很重要!
答案 0 :(得分:15)
Switch语句通常使用跳转表来实现。我认为程序集可以归结为单个指令,这将使它非常快。
唯一可以确定的方法是双向尝试。如果您无法修改现有代码,为什么不只是制作测试应用并在那里试用呢?
答案 1 :(得分:6)
我认为在大多数情况下差异可以忽略不计 - 您的案例可能是一个例外。为什么不组合一个简单的原型应用程序来明确衡量每个解决方案的性能?我的猜测是,这不会超过一个小时的工作......
但是,请考虑代码的清晰度和可维护性。恕我直言,很明显,函数指针解决方案在这方面取得了成功。
更新:另请注意,即使一个解决方案比另一个解决方案速度快两倍,它仍然可能无法证明重写代码的合理性。您应该首先分析您的应用程序,以确定在这些交换机中实际花费了多少执行时间。如果它是总时间的50%,则有理由对其进行优化。如果它仅为几个百分点,那么优化它将是一种浪费。
答案 2 :(得分:2)
PéterTörök有正确的想法尝试两者并计时。你可能不喜欢它,但遗憾的是这是现实情况。 “过早优化”的颂歌是有原因的。
我始终赞成从一开始就使用性能最佳实践,只要它不牺牲清晰度。但在这种情况下,对于你提到的任何一种选择都不是一个明确的胜利。在大多数情况下,这种微小的变化将没有可衡量的影响。将会有一些主要的瓶颈完全控制整个系统的速度。在现代计算机上,这里和那里的一些指令基本上是不可见的,因为系统被内存缓存未命中或管道停顿阻塞,而这些指令很难预测。例如,在您的情况下,单个额外的缓存未命中可能会决定哪个方法会更慢。
现实世界的解决方案是使用分析器评估整个系统的性能。这将显示代码中“热点”的位置。通常的下一步是进行算法更改,以通过更好的算法或缓存来减少对热代码的多次调用的需要。只有当一小部分代码点亮了分析器时,才值得采用像这样的微小优化。那时,你必须尝试不同的东西并测试对速度的影响。如果不衡量变化的影响,即使对于专家来说,你也可能会使情况变得更糟。
所有这一切,我猜想如果参数很少,那么你的情况下的函数调用可能会稍微快一点,特别是如果每个案例的主体都很大。如果switch语句不使用跳转表,那可能会更慢。但它可能会因编译器和机器架构而有很大不同,所以我不会花太多时间在它上面,除非你后来有确凿的证据证明它是你系统的瓶颈。编程与编写新代码一样重要。
答案 3 :(得分:0)
如果你真的想要从那个野兽中吮吸每一个循环,它将需要多次通过,并且猜测不会告诉你要修复什么。 Here's an example of what I mean.
答案 4 :(得分:-1)
在C ++中切换该大小的语句通常需要更好的类组织和多态性的使用。你确定没有办法让你的代码让编译器为你处理函数跳跃/启动吗?
但是为了回答这个问题,switch语句通常会编译成函数表跳转列表。您可以检查汇编器输出以确认您的是否是。因此,对于这种情况,它可能是六个中的一个,六个是另一个。