扫码阅读
手机扫码阅读

Groovy as关键字性能测试

56 2024-04-16

之前写了文章介绍Groovy关键字as,我个人是十分推荐使用,特别在基础类型数据转换场景下,as关键字能够随心所欲将数据转换成我们需要的类型。但在实际使用过程中,由于没看到具体实现,也难以对as关键字的性能有个了解。所以今天准备测试几种我经常使用的场景进行as关键字的性能测试。

这次我准备使用 Java微基准测试神器JMH初探来进行基准测试,自从用上了JMH,就再也没有自己写过基准测试用例了。十分推荐。

String转double

这个是非常常用的,还有一个类似的String转int,由于极其相似就不再测试了。其实结论大差不差。

下面是我的测试用例,分成了两部分,一部分Groovy类,用于实现各种不同方法,一部分是JMH的内容。原因是我还没有找到JMH完美兼容Groovy的方法。

Groovy类:

 class JmhG { static double groovy(String str) {
        str as double } static double java(String str) {
        Double.valueOf(str);
    } static double java2(String str) {
        str.toBigDecimal()
    }
} 

JMH测试Case:

 import com.funtester.frame.SourceCode; import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.results.format.ResultFormatType; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.Throughput) @Warmup(iterations = 2, time = 5, timeUnit = TimeUnit.SECONDS) @Measurement(iterations = 5, time = 10, timeUnit = TimeUnit.SECONDS) @Threads(2) @Fork(1) @State(value = Scope.Thread) @OutputTimeUnit(TimeUnit.MILLISECONDS) public class JmhT extends SourceCode { @Param(value = {"13323222320", "2323230.2323233232", "532873873828382738201"}) private String str; @Benchmark public void groovy() {
        JmhG.groovy(str);
    } @Benchmark public void java() {
        JmhG.java(str);
    } @Benchmark public void javaForce() {
        JmhG.java2(str);
    } public static void main(String[] args) throws RunnerException {
        Options options = new OptionsBuilder()
                .include(JmhT.class.getSimpleName())
                .result("result.json")
                .resultFormat(ResultFormatType.JSON)
                .forks(1)
                .threads(2)
                .warmupIterations(1)
                .warmupBatchSize(1)
                .measurementIterations(2)
                .measurementBatchSize(2)
                .build(); new Runner(options).run();
    }
} 

测试结果:

 Benchmark                       (str)   Mode  Cnt      Score   Error   Units
JmhT.groovy               13323222320  thrpt    2   9314.268          ops/ms
JmhT.groovy        2323230.2323233232  thrpt    2   4219.366          ops/ms
JmhT.groovy     532873873828382738201  thrpt    2   4442.363          ops/ms
JmhT.java                 13323222320  thrpt    2  19418.404          ops/ms
JmhT.java          2323230.2323233232  thrpt    2   5679.708          ops/ms
JmhT.java       532873873828382738201  thrpt    2   6331.530          ops/ms
JmhT.javaForce            13323222320  thrpt    2  27996.119          ops/ms
JmhT.javaForce     2323230.2323233232  thrpt    2   3400.895          ops/ms
JmhT.javaForce  532873873828382738201  thrpt    2   1614.033          ops/ms 

从结果看出来,Java自带的方法Double.valueOf(str)性能最好,Groovy关键字as次之,而org.codehaus.groovy.runtime.StringGroovyMethods#toBigDecimal这个方法的性能有点飘忽不定,在int类型字符串情况下,它性能最高。在较长小数点情况下,又稍逊一筹,到了long类型数据直接崩了。各位可以根据使用场景自行选择。

数字转String

这个用得少,通常直接使用Java自带的加一个空字符串实现。不过趁着这次测试看一下各方面不同的性能表现。

Groovy方法类:

 class Jmh { static String groovy(double number) {
        number as String
    } static String java(double number) {
        number + "" } static String java2(double number) {
        number.toString()
    }
} 

JMH的测试Case就不发了,复用上面的,下面是测试结果:

Benchmark                       (num)   Mode  Cnt      Score   Error   Units
JmhT.groovy               13323222320  thrpt    2   5533.081          ops/ms
JmhT.groovy        2323230.2323233232  thrpt    2   2713.348          ops/ms
JmhT.groovy     532873873828382738201  thrpt    2   2845.852          ops/ms
JmhT.java                 13323222320  thrpt    2   7226.492          ops/ms
JmhT.java          2323230.2323233232  thrpt    2   2572.057          ops/ms
JmhT.java       532873873828382738201  thrpt    2   2652.787          ops/ms
JmhT.javaForce            13323222320  thrpt    2  19337.224          ops/ms
JmhT.javaForce     2323230.2323233232  thrpt    2   3979.556          ops/ms
JmhT.javaForce  532873873828382738201  thrpt    2   3940.559          ops/ms 

可以看出Groovy方法性能明显弱于Java的视线,而两种Java实现性能相差无几。这里建议追求极限性能的使用Java的java.lang.Double#toString()或者java.lang.Double#toString(double)这俩其实是一个方法。

double转int

下面分享一下数字类型之间相互转换,以double转int为例。

Groovy方法类:

class JmhG { static int groovy(double d) {
        d as int } static int java(double d) {
        (int) d
    }
} 

JMH测试方法部分内容:

参数化做了点修改,其他内容不变。

 @Param(value = {"13.20", "2323230.2323233232"}) private double num; 

下面是测试结果:

Benchmark                 (num)   Mode  Cnt       Score   Error   Units
JmhT.groovy               13.20  thrpt    2   16441.947          ops/ms
JmhT.groovy  2323230.2323233232  thrpt    2   13305.805          ops/ms
JmhT.java                 13.20  thrpt    2  846022.670          ops/ms
JmhT.java    2323230.2323233232  thrpt    2  861913.384          ops/ms 

结论差不多,Groovy关键字as的性能更差了。几十倍的差距已经无法直视,后面处理脚本层面会用到groovy关键字as,框架部分和业务部分都会避免使用as关键字了。

结论

结尾放一下Groovy关键字as的总结陈词。

Groovy是一种基于JVM的动态语言,它可以与Java平滑地集成,支持Java的语法和库,并且具有更高的灵活性和易用性。在Groovy中,as是一个关键字,它用于类型转换和类型推断。

在Groovy中,as关键字用于将一个对象转换为指定类型的对象。例如,可以使用as关键字将一个字符串转换为整数,或将一个Map转换为JSON字符串。as关键字还可以用于类型推断,即根据上下文推断出对象的类型。例如,在Groovy中,可以使用def关键字定义一个变量,然后根据赋值语句自动推断出变量的类型。

as关键字的用途有以下几点:

  • 类型转换:as关键字可以将一个对象转换为指定类型的对象,方便程序员进行类型转换操作。

  • 类型推断:as关键字可以根据上下文推断出对象的类型,简化了变量定义和类型转换的代码。

  • 继承和多态:as关键字可以用于继承和多态的场景,比如将一个子类对象转换为父类对象或将一个接口对象转换为实现类对象。

总之,as关键字是Groovy语言的一个重要特性,它可以帮助程序员更方便地进行类型转换和类型推断操作,提高代码的可读性和可维护性,同时也支持继承和多态的特性,方便程序员进行面向对象编程。

原文链接: http://mp.weixin.qq.com/s?__biz=MzU4MTE2NDEyMQ==&mid=2247499175&idx=1&sn=ff56dcf99458b82db6a27e3d2c185072&chksm=fd497091ca3ef9877495296416df1972ec97ca882ee635e8eef6cb37c62233e12d8a5f7214f6#rd