中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Java使用JMH進行基準性能測試分析

發布時間:2021-11-15 09:12:43 來源:億速云 閱讀:162 作者:iii 欄目:開發技術

本篇內容主要講解“Java使用JMH進行基準性能測試分析”,感興趣的朋友不妨來看看。本文介紹的方法操作簡單快捷,實用性強。下面就讓小編來帶大家學習“Java使用JMH進行基準性能測試分析”吧!

    一、前言

    在日常開發工作當中,開發人員可能有這些困惑:自己寫的這個方法性能到底怎么樣?在原接口實現方法中添加了新的業務邏輯,對整個接口的性能影響有多少?有多種實現方式(或開源類庫),到底哪一種性能更好?…

    二、JMH概述

    1、什么是JMH

    ??JMH,即Java Microbenchmark Harness,是專門用于代碼微基準測試的工具套件。何謂Micro Benchmark呢?簡單的來說就是基于方法層面的基準測試,精度可以達到微秒級。其由Oracle/openjdk內部開發JIT編譯器的大佬們所開發,作為java的方法級性能測試工具可以說是根正苗紅了。(官方地址:http://hg.openjdk.java.net/code-tools/jmh/ )

    2、JMH適用的典型場景

    ??a、優化熱點方法,準確的知道某個方法的執行耗時,以及不同入參與最終實際耗時的關系,從而針對性的進行優化;
    ??b、尋找最佳方案,驗證接口方法不同實現方式的實際吞吐量,從而確定最佳實現方式 。如:選擇json轉換工具時選fastjson還是gson、字符串連接使用StringBuilder方式還是直接相加;
    ??c、分析性能損耗,在原接口方法業務邏輯中添加新的業務代碼時,對整個業務方法的性能影響。如:在原業務邏輯中,添加一個插入操作日志的操作,可以分析新加操作對整個業務方法的性能影響。
    ??d、分析百分比內的耗時,即測試方法多次調用時百分比區間內的耗時,如:測試調用某個方法,50%以內的調用耗時是8.2ms/op,90%以內是9.3ms/op,99.99%以內是10.2ms/op,等等。(模式為Mode.SampleTime)

    3、JMH基本概念

    ??a、Mode :表示JMH測試中的模式,默認有5種,分別是Throughput(吞吐量)、AverageTime(平均耗時)、SampleTime(隨機采樣)、SingleShotTime(單次執行)、All(以上4種都來一次);
    ??b、Fork:表示JMH將用來測試的進程數;
    ??c、Warmup : 表示預熱,在HotSpot中,JVM的JIT編譯器會對熱點代碼進行編譯優化, 因此為了最接近真實的情況,需要先預熱測試代碼,使JIT編譯器完成可能需要的優化,從而令JMH最終測試結果更加準確;
    ??d、Iteration :表示JMH中的最小測試迭代單位,即測試次數,一般默認值是每次1s;
    ??e、Benchmark:用于標注JMH將進行測試的方法。(類似Junit中的@Test注解)

    三、JMH的使用

    1、快速跑起來

    ??JMH的基本使用只需2步,第1步是引入maven依賴包,第2步是根據工具框架模板編寫測試類,以下通過一個簡單例子進行詳細說明:

    例1:測試一個方法的平均耗時

    第1步:引入maven依賴: (筆者使用的jmh版本為1.21)

    <!-- JMH -->
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>${jmh.version}</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>${jmh.version}</version>
        <scope>provided</scope>
    </dependency>

    第2步:編寫測試方法:

    package com.xiaojiang;
    
    import org.openjdk.jmh.annotations.Benchmark;
    import org.openjdk.jmh.annotations.BenchmarkMode;
    import org.openjdk.jmh.annotations.Mode;
    import org.openjdk.jmh.annotations.OutputTimeUnit;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    
    import java.util.concurrent.TimeUnit;
    
    /**
     * @ Description:jmh使用第一個例子
     * @ Author     :xiaojiang
     * @ Date       :Created in 2019-06-19
     * @ Version    :0.0.1
     */
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @BenchmarkMode(Mode.AverageTime)
    public class JmhDemoOne {
        public static void main(String[] args) throws Exception{
            Options options = new OptionsBuilder()
                    .include(JmhDemoOne.class.getName())
                    .build();
            new Runner(options).run();
        }
        /**
         * 測試sayHello的平局耗時
         *
         * @throws Exception
         */
        @Benchmark
        public void sayHello() throws Exception{
            //TODO 業務方法 ,此處用休眠的方式模擬業務耗時10 ms
            TimeUnit.MILLISECONDS.sleep(10);
        }
    }

    代碼說明:

    通過以上例子可以發現,一個基本的JMH測試實現其實并不是很復雜,非常類似于用Junit做單元測試。具體說明如下:
    ??a、類名JmhDemoOne 上的@OutputTimeUnit、@BenchmarkMode這兩個注解,表明這是一個JMH的測試類;(具體注解含義 ,以及更多注解說明請參考下文JMH常用注解詳細介紹)
    ??b、主函數入口main方法中指定了一些基本測試參數選項;(基本就是固定寫法。其實有更多相關參數方法可以添加,但這些參數筆者建議通過注解的方式在類上直接添加,這樣來的更加方便)
    ??c、通過@Benchmark注解標注需要benchmark(基準測試)的具體方法;

    直接運行測試方法,控制臺輸出測試結果如下:(筆者JDK版本為1.8,IDE工具為IDEA2018)

    # JMH version: 1.21
    # VM version: JDK 1.8.0_144, Java HotSpot(TM) 64-Bit Server VM, 25.144-b01
    # VM invoker: D:\Java\jdk1.8.0_144\jre\bin\java.exe
    # VM options: -javaagent:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.5\lib\idea_rt.jar=55987:D:\Program Files\JetBrains\IntelliJ IDEA 2018.2.5\bin -Dfile.encoding=UTF-8
    # Warmup: 5 iterations, 10 s each
    # Measurement: 5 iterations, 10 s each
    # Timeout: 10 min per iteration
    # Threads: 1 thread, will synchronize iterations
    # Benchmark mode: Average time, time/op
    # Benchmark: com.xiaojiang.JmhDemoOne.sayHello
    
    # Run progress: 0.00% complete, ETA 00:08:20
    # Fork: 1 of 5
    # Warmup Iteration   1: 10.716 ms/op
    # Warmup Iteration   2: 10.640 ms/op
    # Warmup Iteration   3: 10.737 ms/op
    # Warmup Iteration   4: 10.693 ms/op
    # Warmup Iteration   5: 10.723 ms/op
    Iteration   1: 10.716 ms/op
    Iteration   2: 10.724 ms/op
    Iteration   3: 10.772 ms/op
    Iteration   4: 10.758 ms/op
    Iteration   5: 10.709 ms/op
    
    # Run progress: 20.00% complete, ETA 00:06:43
    # Fork: 2 of 5
    # Warmup Iteration   1: 10.744 ms/op
    # Warmup Iteration   2: 10.732 ms/op
    # Warmup Iteration   3: 10.748 ms/op
    # Warmup Iteration   4: 10.728 ms/op
    # Warmup Iteration   5: 10.760 ms/op
    Iteration   1: 10.701 ms/op
    Iteration   2: 10.709 ms/op
    Iteration   3: 10.719 ms/op
    Iteration   4: 10.714 ms/op
    Iteration   5: 10.703 ms/op
    
    # Run progress: 40.00% complete, ETA 00:05:02
    # Fork: 3 of 5
    # Warmup Iteration   1: 10.729 ms/op
    # Warmup Iteration   2: 10.731 ms/op
    # Warmup Iteration   3: 10.728 ms/op
    # Warmup Iteration   4: 10.700 ms/op
    # Warmup Iteration   5: 10.709 ms/op
    Iteration   1: 10.708 ms/op
    Iteration   2: 10.701 ms/op
    Iteration   3: 10.708 ms/op
    Iteration   4: 10.726 ms/op
    Iteration   5: 10.698 ms/op
    
    # Run progress: 60.00% complete, ETA 00:03:21
    # Fork: 4 of 5
    # Warmup Iteration   1: 10.724 ms/op
    # Warmup Iteration   2: 10.688 ms/op
    # Warmup Iteration   3: 10.748 ms/op
    # Warmup Iteration   4: 10.732 ms/op
    # Warmup Iteration   5: 10.772 ms/op
    Iteration   1: 10.729 ms/op
    Iteration   2: 10.688 ms/op
    Iteration   3: 10.705 ms/op
    Iteration   4: 10.687 ms/op
    Iteration   5: 10.709 ms/op
    
    # Run progress: 80.00% complete, ETA 00:01:40
    # Fork: 5 of 5
    # Warmup Iteration   1: 10.688 ms/op
    # Warmup Iteration   2: 10.696 ms/op
    # Warmup Iteration   3: 10.692 ms/op
    # Warmup Iteration   4: 10.684 ms/op
    # Warmup Iteration   5: 10.683 ms/op
    Iteration   1: 10.719 ms/op
    Iteration   2: 10.720 ms/op
    Iteration   3: 10.695 ms/op
    Iteration   4: 10.710 ms/op
    Iteration   5: 10.760 ms/op
    
    
    Result "com.xiaojiang.JmhDemoOne.sayHello":
      10.716 ±(99.9%) 0.016 ms/op [Average]
      (min, avg, max) = (10.687, 10.716, 10.772), stdev = 0.021
      CI (99.9%): [10.700, 10.731] (assumes normal distribution)
    
    
    # Run complete. Total time: 00:08:24
    
    REMEMBER: The numbers below are just data. To gain reusable insights, you need to follow up on
    why the numbers are the way they are. Use profilers (see -prof, -lprof), design factorial
    experiments, perform baseline and negative tests that provide experimental control, make sure
    the benchmarking environment is safe on JVM/OS/HW level, ask for reviews from the domain experts.
    Do not assume the numbers tell you what you want them to tell.
    
    Benchmark            Mode  Cnt   Score   Error  Units
    JmhDemoOne.sayHello  avgt   25  10.716 ± 0.016  ms/op
    
    Process finished with exit code 0

    測試結果說明:
    整個測試結果分為3大塊,測試基本參數信息、測試過程、測試結果,各行含義具體說明如下:

    說明
    參數信息(1-10行)1:jmh版本
    2:jvm版本信息
    3:jvm程序(jdk安裝路徑)
    4:jvm參數配置
    5:預熱參數:預熱次數、每次持續時間
    6:測試參數:測試次數、每次持續時間
    7:每次測試迭代超時時間
    8:每個測試進程的測試線程數
    9: 測試的模式
    10:測試的方法
    測試過程(12-75行)12-23:第1次fork測試 (fork可以理解為1個獨立的進程)
    12:測試完成進度,預計剩余需要時間
    13:當前第幾次fork
    14-18:預熱執行,每次預熱執行耗時
    19-23:正式測試執行,每次測試執行耗時
    25-36:第2次fork測試
    38-49:第3次fork測試
    51-62:第4次fork測試
    64-75:第5次fork測試
    測試結果(78-95行)78-81:測試結果,包括測試的方法、平均耗時[平局耗時的比例]、最大最小 耗時、測試結果數據離散度(stdev)等
    84:測試總耗時
    86-90:對測試結果的解釋
    92-93:測試結論{測試的方法、測試類型(Mode)、測試總次數(Cnt)、測試結果(Score)、誤差(Error)、單位(Units)}
    95:結束

     注:
    ??a、測試結果中的Measurement、Fork、Warmup等參數,是JMH采用了默認的配置值,實際使用中,我們可根據需要指定相關參數。
    ??b、運行這個測試類可以在IDEA中直接跑,也可以打成 jar 包到服務器上跑。
    ??c、本測試結果是直接輸出在控制臺,如有需要,可將測試結果輸出到文件中,方法是在options中添加output方法指定測試結果輸出目錄,如下:

    Options options = new OptionsBuilder()
            .include(JmhDemoOne.class.getName())
            .output("D:/JmhDemoOne.log")   //將測試結果輸出到指定目錄文件
            .build();

    2、JMH常用注解詳細介紹

    注解介紹
    @BenchmarkMode基準測試模式。一共有5種可選值:(其實是4種)
    Mode.Throughput:吞吐量模式,即單位時間內方法的吞吐量
    Mode.AverageTime:平均耗時模式,即一定測試次數內方法執行的平均耗時
    Mode.SampleTime:隨機采樣模式,即最終結果為取樣結果分布比例
    Mode.SingleShotTime:單次執行模式,即只會執行一次(以上的模式通常會有預熱、會迭代執行多次,這個模式可用于測試某些特定場景,如冷啟動時的性能)
    Mode.All:即以上模式都執行一遍

    -----------------------------------
    用法示例:(benchmark模式為平均耗時模式)
    @BenchmarkMode(Mode.AverageTime)
    @OutputTimeUnit測試結果的時間單位。其值為java.util.concurrent.TimeUnit 枚舉中的值,通常用的值是秒、毫秒、微妙(需要注意的是,在不同測試模式下,需要選擇合適的時間單位,從而獲取更精確的測試結果。)

    ------------------------------------
    用法示例:(benchmark結果時間單位為毫秒)
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @Benchmark基準測試,方法級注解(配置在方法名上)。用于標注需要進行benchmark (基準測試)的方法

    ------------------------------------
    用法示例:(方法需要benchmark)
    @Benchmark
    @Warmup預熱參數。配置預熱的相關參數,參數含義是:iterations(預熱次數)、time (預熱時間)、timeUnit (時間單位)

    ------------------------------------
    用法示例:(預熱10次,每次20s)
    @Warmup(iterations = 10, time = 20, timeUnit = TimeUnit.SECONDS)
    @Measurement度量,即benchmark基本參數。參數含義是:iterations(測試次數)、time (每次測試時間)、timeUnit (時間單位)

    ------------------------------------
    用法示例:(測試5次,每次30s)
    @Measurement(iterations = 5, time = 30, timeUnit = TimeUnit.SECONDS)
    @Fork分叉,即進程數。用于配置將使用多少個進程進行測試

    ------------------------------------
    用法示例:(使用3個進程)
    @Fork(3)
    @Threads線程數。每個Fork(進程)中的線程數,一般可設為測試機器cpu核心數。

    ------------------------------------
    用法示例:(使用4個線程)
    @Threads(4)
    @Param成員參數,屬性級注解。用于測試方法在不同入參情況下的性能表現。

    ------------------------------------
    用法示例:(入參值依次為1 、10、100)
    @Param({“1”, “10”, “100”})
    @Setup設置,方法級注解。用于標注benchmark前的操作,通常用于測試前初始化參數資源,如初始化數據庫連接等。

    ------------------------------------
    用法示例:(初始化方法)
    @Setup
    @TearDown拆卸,方法級注解。用于標注benchmark后的操作,通常用于測試后回收資源,如關閉數據庫連接等。

    ------------------------------------
    用法示例:(回收方法)
    @TearDown
    @State狀態,表示一個類/方法的可用范圍,其值有3個:
    Scope.Thread:默認狀態,每個線程分配一個獨享的實例;
    Scope.Benchmark:測試中的所有線程共享實例;(多線程測試情況下)
    Scope.Group:同一個組的線程共享實例;

    ------------------------------------
    用法示例:(默認值,每個線程分配一個實例)
    @State(Scope.Thread)
    @Group測試組,方法級注解。適用分組測試,每組線程數不一樣的場景。

    ------------------------------------
    用法示例:(組名為“group_name”的一個組)
    @Group(“group_name”)
    @GroupThreads組線程數,方法級注解。通常和@Group搭配使用

    ------------------------------------
    用法示例:(組線程數為10)
    @GroupThreads(10)
    @Timeout超時時間。每次測試迭代超時時間

    ------------------------------------
    用法示例:(每次測試超時時間為20min)
    @Timeout(time = 20, timeUnit = TimeUnit.MINUTES)

    以上是使用JMH測試中常用的注解,當然JMH還有一些其它注解,如@CompilerControl、@AuxCounters 等等,這些注解通常可用于滿足特定的測試場景需求,具體相關使用如有需要,可參考官方示例,官方demo比較詳細,比較好理解學習。

    3、更多示例

    本小節筆者將通過幾個小示例,展示JMH的基本使用。
    例2:
    測試驗證字符串連接處理時,使用StringBuilder方式是否比直接相加好。

    package com.xiaojiang;
    
    import org.openjdk.jmh.annotations.*;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    import java.util.concurrent.TimeUnit;
    /**
     * @ Description:jmh使用第二個例子
     * @ Author     :xiaojiang
     * @ Date       :Created in 2019-06-19
     * @ Version    :0.0.1
     */
    @OutputTimeUnit(TimeUnit.SECONDS)
    @BenchmarkMode(Mode.Throughput)
    @Warmup(iterations = 5, time = 1, timeUnit = TimeUnit.MILLISECONDS)
    @Measurement(iterations = 10, time = 5, timeUnit = TimeUnit.SECONDS)
    @State(Scope.Thread)
    public class JmhDemoTwo {
        public static void main(String[] args) throws Exception{
            Options options = new OptionsBuilder()
                    .include(JmhDemoTwo.class.getName())
                    .build();
            new Runner(options).run();
        }
        /**
         * 字符串個數
         */
        @Param({"10", "100", "1000"})
        private int number;
        /**
         * 字符串直接相加方式
         */
        @Benchmark
        public void StringAddMode(){
            String str = "";
            for(int i=0;i<number;i++){
                str = str + i;
            }
        }
        /**
         * 字符串通過StringBuilder的append方式
         */
        @Benchmark
        public void StringBuilderMode(){
            StringBuilder sb = new StringBuilder();
            for(int i=0;i<number;i++){
                sb.append(i);
            }
        }
    }

    測試結果:

    //---省略測試過程結果----------
    Benchmark                     (number)   Mode  Cnt         Score        Error  Units
    JmhDemoTwo.StringAddMode            10  thrpt   50   7670608.558 ±  99068.181  ops/s
    JmhDemoTwo.StringAddMode           100  thrpt   50    437133.436 ±   7738.031  ops/s
    JmhDemoTwo.StringAddMode          1000  thrpt   50      4023.846 ±     62.872  ops/s
    JmhDemoTwo.StringBuilderMode        10  thrpt   50  22608867.036 ± 669332.843  ops/s
    JmhDemoTwo.StringBuilderMode       100  thrpt   50   1232847.661 ±  23742.088  ops/s
    JmhDemoTwo.StringBuilderMode      1000  thrpt   50     98367.745 ±   1487.840  ops/s

    從測試結果可以看出,在字符串連接數量分別為10、100、1000時,通過StringBuilder處理字符串的方式比直接相加的方式性能都要強一些;如,當字符竄數量為1000時,直接相加方式的方法吞吐量為4023.846 ops/s,StringBuilder的方式方法吞吐量達到 98367.745ops/s 。(當然具體測試結果值和機器配置、JVM配置有關)

    例3:
    測試常用序列化json庫fastJson、gson、jackson的性能(均為截止2019.06最新版本)。

    package com.xiaojiang;
    
    import org.openjdk.jmh.annotations.*;
    import org.openjdk.jmh.runner.Runner;
    import org.openjdk.jmh.runner.options.Options;
    import org.openjdk.jmh.runner.options.OptionsBuilder;
    
    import java.util.ArrayList;
    import java.util.Date;
    import java.util.List;
    import java.util.concurrent.TimeUnit;
    /**
     * @ Description:jmh使用第三個例子
     * @ Author     :xiaojiang
     * @ Date       :Created in 2019-06-19
     * @ Version    :0.0.1
     */
    @OutputTimeUnit(TimeUnit.MILLISECONDS)
    @BenchmarkMode(Mode.SingleShotTime)
    @Warmup(iterations = 5)
    @Measurement(iterations = 1)
    @State(Scope.Benchmark)
    @Fork(1)
    public class JmhDemoThree {
        public static void main(String[] args) throws Exception{
            Options options = new OptionsBuilder()
                    .include(JmhDemoThree.class.getName())
                    .build();
            new Runner(options).run();
        }
        /**
         * 序列化次數
         */
        @Param({"100", "10000", "1000000"})
        private int number;
        private Userinfo userinfo;
        private String fastjson_jsonStr;
        private String gson_jsonStr;
        private String jackson_jsonStr;
        /**
         *  fastjson bean2Json
         */
        @Benchmark
        public void fastjson_bean2Json(){
            for (int i=0;i<number;i++){
                JsonUtil.fastjson_bean2Json(userinfo);
            }
        }
        /**
         *  gson bean2Json
         */
        @Benchmark
        public void gson_bean2Json(){
            for (int i=0;i<number;i++){
                JsonUtil.gson_bean2Json(userinfo);
            }
        }
        /**
         *  jackson bean2Json
         */
        @Benchmark
        public void jackson_bean2Json(){
            for (int i=0;i<number;i++){
                JsonUtil.jackson_bean2Json(userinfo);
            }
        }
        /**
         *  fastjson json2Bean
         */
        @Benchmark
        public void fastjson_json2Bean(){
            for (int i=0;i<number;i++){
                JsonUtil.fastjson_json2Bean(fastjson_jsonStr,Userinfo.class);
            }
        }
        /**
         *  gson json2Bean
         */
        @Benchmark
        public void gson_json2Bean(){
            for (int i=0;i<number;i++){
                JsonUtil.gson_json2Bean(gson_jsonStr,Userinfo.class);
            }
        }
        /**
         *  jackson json2Bean
         */
        @Benchmark
        public void jackson_json2Bean(){
            for (int i=0;i<number;i++){
                JsonUtil.jackson_json2Bean(jackson_jsonStr,Userinfo.class);
            }
        }
        /**
         * 初始化參數
         */
        @Setup
        public void init(){
             userinfo = new Userinfo();
            userinfo.setUsername("張三");
            userinfo.setGender("男");
            userinfo.setAge(18);
            userinfo.setBirthday(new Date());
            userinfo.setCreateTime(System.currentTimeMillis());
            List<String> list = new ArrayList<>();
            list.add("北京三里屯兒那條街那條巷那一號");
            list.add("上海三里屯兒那條街那條巷那一號");
            list.add("深圳三里屯兒那條街那條巷那一號");
            userinfo.setAddress(list);
            
            fastjson_jsonStr = JsonUtil.fastjson_bean2Json(userinfo);
            gson_jsonStr = JsonUtil.gson_bean2Json(userinfo);
            jackson_jsonStr = JsonUtil.jackson_bean2Json(userinfo);
        }
    }

    (其它相關代碼后附)

    測試結果:

    //---省略測試過程結果----------
    Benchmark                        (number)  Mode  Cnt     Score   Error  Units
    JmhDemoThree.fastjson_bean2Json       100    ss          1.586          ms/op
    JmhDemoThree.fastjson_bean2Json     10000    ss          3.683          ms/op
    JmhDemoThree.fastjson_bean2Json   1000000    ss        500.924          ms/op
    JmhDemoThree.fastjson_json2Bean       100    ss          0.978          ms/op
    JmhDemoThree.fastjson_json2Bean     10000    ss          5.493          ms/op
    JmhDemoThree.fastjson_json2Bean   1000000    ss        362.337          ms/op
    JmhDemoThree.gson_bean2Json           100    ss          2.106          ms/op
    JmhDemoThree.gson_bean2Json         10000    ss         28.693          ms/op
    JmhDemoThree.gson_bean2Json       1000000    ss       1890.999          ms/op
    JmhDemoThree.gson_json2Bean           100    ss          7.175          ms/op
    JmhDemoThree.gson_json2Bean         10000    ss        110.298          ms/op
    JmhDemoThree.gson_json2Bean       1000000    ss       7310.555          ms/op
    JmhDemoThree.jackson_bean2Json        100    ss          2.111          ms/op
    JmhDemoThree.jackson_bean2Json      10000    ss          8.859          ms/op
    JmhDemoThree.jackson_bean2Json    1000000    ss        376.587          ms/op
    JmhDemoThree.jackson_json2Bean        100    ss          1.992          ms/op
    JmhDemoThree.jackson_json2Bean      10000    ss         10.723          ms/op
    JmhDemoThree.jackson_json2Bean    1000000    ss        714.569          ms/op

    從測試結果可以看出,不論是bean2Json還是json2Bean,fastjson的性能比gson、jackson都要好一些,當然,jackson性能也很不錯(不愧是spring默認的序列化和反序列化工具),尤其是當序列化與反序列化次數較多時,fastjson優勢尤其明顯。當然,由于筆者用于測試的實體bean數據結構還是較為簡單,在一些較為復雜的數據結構場景下,其各自的性能表現可能有所不一樣。(筆者用的測試Mode是Mode.SingleShotTime,只測試一次,且由于機器等原因,所以誤差可能相對較大。有興趣的讀者,可以測試一下不同測試Mode下,更復雜的數據結構場景下,各序列化/反序列化工具的性能表現)

    四、小結

    1、JMH官方并沒有提供比較詳細的使用文檔(這也是筆者整理本文的重要原因),但是其提供了許多詳細、較容易理解的例子,有問題的可以參考,地址為:http://hg.openjdk.java.net/code-tools/jmh/file/99d7b73cf1e3/jmh-samples/src/main/java/org/openjdk/jmh/samples 。
    2、JMH中的參數配置,許多參數可以直接在main方法的options中設置,也可以通過在類上直接添加注解配置。
    3、注意:跑測試的時候要直接用run的方式跑,不要用debug的方式跑,否則會出錯。
    4、JMH適用于方法級別的基準性能測試,并不適用于跨系統、跨服務之間的全鏈路測試。
    5、使用JMH基準測試,雖然精度可以達到微妙級,但是測試結果依然是會存在一定誤差的;由于測試機器、場景、jvm配置等不同而引起測試誤差是完全可能的,只是這個誤差能否在可接受的范圍內。
    6、最終測試結果是fork參數與每次測試迭代參數的合集,如fork值為3,iterations值為5,那最終測試次數就是 3 * 5 = 15次。

    參考文章:
    http://hg.openjdk.java.net/code-tools/jmh/file/99d7b73cf1e3/jmh-samples/src/main/java/org/openjdk/jmh/samples
    http://java-performance.info/jmh/
    https://www.cnblogs.com/tranquillity/p/9488572.html
    https://www.xncoding.com/2018/01/07/java/jmh.html
    https://blog.csdn.net/lxbjkben/article/details/79410740
    http://blog.dyngr.com/blog/2016/10/29/introduction-of-jmh/
    http://irfen.me/java-jmh-simple-microbenchmark/
    https://www.cnblogs.com/bestzhang/p/10082119.html

    附:

    json工具pom依賴:

    <!--fastJson-->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.58</version>
    </dependency>
    <!--gson-->
    <dependency>
        <groupId>com.google.code.gson</groupId>
        <artifactId>gson</artifactId>
        <version>2.8.5</version>
    </dependency>
    <!--jackson-->
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-databind</artifactId>
        <version>2.9.9</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-core</artifactId>
        <version>2.9.9</version>
    </dependency>
    <dependency>
        <groupId>com.fasterxml.jackson.core</groupId>
        <artifactId>jackson-annotations</artifactId>
        <version>2.9.9</version>
    </dependency>

    Userinfo.java:

    package com.xiaojiang;
    
    import java.util.Date;
    import java.util.List;
    /**
     * @ Description:用戶信息
     * @ Author     :xiaojiang
     * @ Date       :Created in 2019-06-19
     * @ Version    :0.0.1
     */
    public class Userinfo {
        private String username;    //用戶名
        private String gender;      //用戶性別
        private Integer age;    //用戶年齡
        private Date birthday;      //用戶生日
        private List<String> address;   //  用戶地址
        private Long createTime;    //用戶創建時間
    
        public String getUsername() {
            return username;
        }
    
        public void setUsername(String username) {
            this.username = username;
        }
    
        public String getGender() {
            return gender;
        }
    
        public void setGender(String gender) {
            this.gender = gender;
        }
    
        public Integer getAge() {
            return age;
        }
    
        public void setAge(Integer age) {
            this.age = age;
        }
    
        public Date getBirthday() {
            return birthday;
        }
    
        public void setBirthday(Date birthday) {
            this.birthday = birthday;
        }
    
        public List<String> getAddress() {
            return address;
        }
    
        public void setAddress(List<String> address) {
            this.address = address;
        }
    
        public Long getCreateTime() {
            return createTime;
        }
    
        public void setCreateTime(Long createTime) {
            this.createTime = createTime;
        }
    
        @Override
        public String toString() {
            return "Userinfo{" +
                    "username='" + username + '\'' +
                    ", gender='" + gender + '\'' +
                    ", age=" + age +
                    ", birthday=" + birthday +
                    ", address=" + address +
                    ", createTime=" + createTime +
                    '}';
        }
    }

    JsonUtil.java:

    package com.xiaojiang;
    
    import com.alibaba.fastjson.JSON;
    import com.fasterxml.jackson.core.JsonProcessingException;
    
    import java.io.IOException;
    
    /**
     * @ Description:json工具類
     * @ Author     :xiaojiang
     * @ Date       :Created in 2019-06-19
     * @ Version    :0.0.1
     */
    public class JsonUtil {
    
        private static com.google.gson.Gson gson = new com.google.gson.GsonBuilder().create();
        private static com.fasterxml.jackson.databind.ObjectMapper jacksonMapper = new com.fasterxml.jackson.databind.ObjectMapper();
    
        public static String fastjson_bean2Json(Object object){
            return com.alibaba.fastjson.JSON.toJSONString(object);
        }
    
        public static <T> T fastjson_json2Bean(String jsonStr, Class<T> objectClass) {
            return JSON.parseObject(jsonStr, objectClass);
        }
    
        public static String gson_bean2Json(Object object){
            return gson.toJson(object);
        }
    
        public static <T> T gson_json2Bean(String jsonStr, Class<T> objectClass){
            return gson.fromJson(jsonStr,objectClass);
        }
    
        public static String jackson_bean2Json(Object object) {
            try {
                return jacksonMapper.writeValueAsString(object);
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
            return null;
        }
    
        public static <T> T jackson_json2Bean(String jsonStr, Class<T> objectClass){
            try {
                return jacksonMapper.readValue(jsonStr,objectClass);
            } catch (IOException e) {
                e.printStackTrace();
            }
            return null;
        }
    }

    到此,相信大家對“Java使用JMH進行基準性能測試分析”有了更深的了解,不妨來實際操作一番吧!這里是億速云網站,更多相關內容可以進入相關頻道進行查詢,關注我們,繼續學習!

    向AI問一下細節

    免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

    AI

    商南县| 伊金霍洛旗| 六安市| 峨边| 门头沟区| 玉溪市| 壤塘县| 孟连| 凤冈县| 磐石市| 连城县| 博罗县| 黄浦区| 辽阳县| 万盛区| 板桥市| 万安县| 云梦县| 琼结县| 昌江| 赤峰市| 牡丹江市| 双流县| 重庆市| 农安县| 城步| 泽库县| 陆良县| 墨脱县| 溆浦县| 新宁县| 赣州市| 辉南县| 荃湾区| 宁津县| 任丘市| 浦县| 辛集市| 嘉黎县| 凤阳县| 盐津县|