Origin
最近给dubbo提了个pr,内容大概是在exchangeClient个数为2的n次方的时候使用与运算来提升性能,dubbo那边的人给的建议是不要用SPI增加程序复杂度(我觉得不用白不用就用了23333) 并且 做个性能测试
Action
首先,java的基准测试一定要使用JMH,因为JIT会做很多性能的优化,比如无用代码消除(你写个超大的for循环发现代码基本不耗时,are you sure?).
那么我写了个基准测试类:
代码如下
//基准测试类型
@BenchmarkMode(Mode.AverageTime)
//基准测试结果的时间类型
@OutputTimeUnit(TimeUnit.NANOSECONDS)
//预热的迭代次数
@Warmup(iterations = 10)
//度量:iterations进行测试的轮次,time每轮进行的时长,timeUnit时长单位,batchSize批次数量
@State(Scope.Thread)
@Measurement(iterations = 10, time = 2, timeUnit = TimeUnit.SECONDS, batchSize = 1)
//循环次数
public class TestPower {
private int size = 2 << 1;
private Object[] mObject = new Object[size];
private final AtomicInteger idx = new AtomicInteger();
{
IntStream.range(0, size).forEach(i -> {
mObject[i] = new Object();
});
}
@Benchmark
public Object power() {
return mObject[idx.getAndIncrement() & size - 1];
}
@Benchmark
public Object normal() {
return mObject[idx.getAndIncrement() % size];
}
public static void main(String[] args) {
try {
Options opt = new OptionsBuilder()
.include(TestPower.class.getSimpleName())
.forks(1)
.build();
new Runner(opt).run();
} catch (Exception e) {
e.printStackTrace();
}
}
}
RESULT
这个时候我们来看看size分别为2的1,2,3,4,5,6,7,8次方的基准测试结果吧
size | using % | using & |
---|---|---|
2^1 | 14.523 ± 0.371 ns/op | 8.680 ± 0.115 ns/op |
2^2 | 14.189 ± 0.035 ns/op | 8.566 ± 0.015 ns/op |
2^3 | 14.342 ± 0.413 ns/op | 8.674 ± 0.158 ns/op |
2^4 | 14.445 ± 0.336 ns/op | 8.557 ± 0.120 ns/op |
2^5 | 14.327 ± 0.162 ns/op | 8.655 ± 0.142 ns/op |
2^6 | 14.330 ± 0.312 ns/op | 8.605 ± 0.064 ns/op |
2^7 | 14.288 ± 0.189 ns/op | 8.621 ± 0.040 ns/op |
2^8 | 14.304 ± 0.334 ns/op | 8.657 ± 0.126 ns/op |
很明显,提升还是非常显著的,HashMap诚不我欺