2015-04-04 77 views
0

说我有以下switch声明:TABLESWITCH性能提升?

switch (i) 
{ 
    case 0: ...; return ...; 
    case 1: ...; return ...; 
    case 2: ...; return ...; 
    case 400: ...; return ...; 
    case 401: ...; return ...; 
    case 402: ...; return ...; 
} 

由于差距太大,编译器生成在这里合理TABLESWITCHO(1)复杂)指令,它采用了LOOKUPSWITCHO(log n)复杂性)。是否有可能通过拆分switch增加这个代码的性能分为两个这样的:

switch (i) 
{ 
    case 0: ...; return ...; 
    case 1: ...; return ...; 
    case 2: ...; return ...; 
} 

switch (i) 
{ 
    case 400: ...; return ...; 
    case 401: ...; return ...; 
    case 402: ...; return ...; 
} 

这将导致编译器生成两个TABLESWITCH而不是一个LOOKUPSWITCH

+0

1)[过早优化是万恶之源](http://en.wikipedia.org/wiki/Program_optimization#When_to_optimize)(Donald Knuth)。 2)为什么不简单地使用地图? – Seelenvirtuose 2015-04-04 13:08:55

+0

因为地图需要装箱,这对我的需求来说太低效了。另外,我的使用案例对性能至关重要,所以我可以乐于接受过早的优化。 – Clashsoft 2015-04-04 13:20:42

+0

那么为什么不使用数组呢?数组查找肯定比方法调度便宜。如果你没有注意到这一点,我非常怀疑你的说法是否有证据支持。 – chrylis 2015-04-04 13:22:26

回答

2

不要花太多时间来尝试优化字节码。字节码不一定反映JIT编译方法的性能。你为什么不采取JMH并自己检查两个案例的实际表现?

事实上,热点C2编译器会将tableswitchlookupswitch以类似的方式,它需要的lookupswitch具有与差距顺序标签很好的照顾。

这两种情况都以类似二进制搜索的方式转换为比较和条件跳转指令序列,并且在性能方面几乎完全相同。

+0

好吧,我自己做了测试:平均1000 * 1000000开关指令在随机整数0..199上,匹配区域0..10和100..110:单开关14538.13毫秒,分开开关15209.492毫秒 – Clashsoft 2015-04-04 13:39:59

+1

@Clashsoft问题这个基准是可预测性。对于随机输入,分支是不可预测的,并且一些数字预处理(例如,将400 + x转换为3 + x)可能是有益的。对于真实的输入,结果可能完全不同。 – maaartinus 2015-04-04 17:53:45