Home Tags Posts tagged with "代码"

代码

0 41

If,Switch不可避免的出现在我们的代码之中,那么为提升运行速度,我们是否可以对这两种语句进行优化呢,答案是肯定的,特此记录;

当我们在项目中需要编写大量的IF else来判断程序逻辑的时候,可以考虑采用switch,当然也可以使用面向对象的思想将其抽象为一个类再通过传参调用相应的逻辑,但这样可能会引起对象过多而浪费性能,因此,优化的目的始终是为了保证程序的正常运行!!!(多被动优化,少主动优化)

 

转载自:

https://mp.weixin.qq.com/s?__biz=MzU1NTkwODE4Mw==&mid=2247485235&idx=1&sn=745db76bf3c07736b227c406ae365638&scene=21#wechat_redirect

 

验证过程及结论:

我们依然借助 Oracle 官方提供的 JMH(Java Microbenchmark Harness,JAVA 微基准测试套件)框架来进行测试,首先引入 JMH 框架,在 pom.xml 文件中添加如下配置:

<!-- https://mvnrepository.com/artifact/org.openjdk.jmh/jmh-core -->
<dependency>
   <groupId>org.openjdk.jmh</groupId>
   <artifactId>jmh-core</artifactId>
   <version>1.23</version>
</dependency>

然后编写测试代码,我们这里添加 5 个条件判断分支,具体实现代码如下:

以上代码的测试结果如下:

结论:

从以上结果可以看出(Score 列),switch 的平均执行完成时间比 if 的平均执行完成时间快了约 2.33 倍

性能分析:

为什么 switch 的性能会比 if 的性能高这么多?

这需要从他们字节码说起,我们把他们的代码使用 javac 生成字节码如下所示:

这些字节码中最重要的信息是“getstatic     #15”,这段代码表示取出“_NUM”变量和条件进行判断。

从上面的字节码可以看出,在 switch 中只取出了一次变量和条件进行比较,而 if 中每次都会取出变量和条件进行比较,因此 if 的效率就会比 switch 慢很多

提升测试量

前面的测试代码我们使用了 5 个分支条件来测试了 if 和 switch 的性能,那如果把分支的判断条件增加 3 倍(15 个)时,测试的结果又会怎么呢?

增加至 15 个分支判断的实现代码如下:

以上代码的测试结果如下:

从 Score 的值可以看出,当分支判断增加至 15 个,switch 的性能比 if 的性能高出了约 3.7 倍,而之前有 5 个分支判断时的测试结果为,switch 的性能比 if 的性能高出了约 2.3 倍,也就是说分支的判断条件越多,switch 性能高的特性体现的就越明显

Switch生成字节码的两种形态:

  • tableswitch
  • lookupswitch

决定因素:决定最终生成的代码使用那种形态取决于 switch 的判断添加是否紧凑

case 是 1…2…3…4 这种依次递增的判断条件时,使用的是 tableswitch

case 是 1…33…55…22 这种非紧凑型的判断条件时则会使用 lookupswitch

代码测试:

 

tableswitch VS lookupSwitchTest

当执行一次 tableswitch 时,堆栈顶部的 int 值直接用作表中的索引,以便抓取跳转目标并立即执行跳转。也就是说 tableswitch 的存储结构类似于数组,是直接用索引获取元素的,所以整个查询的时间复杂度是 O(1),这也意味着它的搜索速度非常快。

而执行 lookupswitch 时,会逐个进行分支比较或者使用二分法进行查询,因此查询时间复杂度是 O(log n),所以使用 lookupswitch 会比 tableswitch 慢

结论:tableswitch是索引查找,lookupswitch是二分查找;

代码测试:

测试结果:

结论:tableswitch 的性能比 lookupwitch 的性能快了约 1.3 倍。但即使这样 lookupwitch 依然比 if 查询性能要高很多。

 

总结:switch 的判断条件是 5 个时,性能比 if 高出了约 2.3 倍,而当判断条件的数量越多时,他们的性能相差就越大。而 switch 在编译为字节码时,会根据 switch 的判断条件是否紧凑生成两种代码:tableswitch(紧凑时生成)和 lookupswitch(非紧凑时生成),其中 tableswitch 是采用类似于数组的存储结构,直接根据索引查询元素;而 lookupswitch 则需要逐个查询或者使用二分法查询,因此 tableswitch 的性能会比 lookupswitch 的性能高,但无论如何 switch 的性能都比 if 的性能要高