这两天我升级了缓存类库 westcache( github /bingoohuang/westcache) 和 SQL 类库 eql( github /bingoohuang/eql),以使得二者更加方便的集成,比如以下写法:
@EqlerConfig
public interface DictDao {
@WestCacheable // westcache注解
@Sql("select id, name, addr from cache_dict") // Eql注解
List<CacheDictBean> selectAll();
}
我很快就把二者集成的实现写好了,但是发现应用启动由原来的大概50秒,慢吞吞地变成了5分多钟,OMG,要疯了,这还受得了。
很快,我就定位到了问题,原来是 westcache 里面的有一处实现,利用了异常 NoSuchMethodException 来查找方法是否在一个 class 中存在,我意识到这很可能是一个问题,因为我早就耳闻异常造成的性能低下。我尝试将它改造成不使用异常的方式来实现,改完后,再测试,应用启动时间就马上降下来了,恢复到原来差不多的时间。
于是,我单独写了一个 基准测试( github /bingoohuang/javacode-demo/blob/master/src/main/java/org/n3r/sandbox/seckill/MethodSearchWaysCompare.java) 来模拟一下两种情况,形成一个比对,运行结果如下:
Benchmark Mode Samples Score Error Units
o.n.s.s.MethodSearchWaysCompare.methodNotFoundException thrpt 10 470604.189 ± 80316.210 ops/s
o.n.s.s.MethodSearchWaysCompare.methodsSearch thrpt 10 1295466.093 ± 34110.967 ops/s
可以看到,不使用异常的吞吐量比使用异常的快一个数量级。可见,异常在循环中,或者高并发处理中,还是要慎用,否则很可能就成了性能杀手。
覆写 Throwable.fillInStackTrace 直接 return this,可以显著提高性能。Benchmark( gist.github /Bpazy/4325c74817869011e9972fce6b1e7b0d)
Benchmark Mode Cnt Score Error Units
Main.testDefaultException thrpt 10 927279.457 ± 53914.733 ops/s
Main.testFillException thrpt 10 55244417.124 ± 2881609.190 ops/s
Main.testNormal thrpt 10 3184321025.595 ± 55475346.833 ops/s
