欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

詳解Java使用JMH進(jìn)行基準(zhǔn)性能測(cè)試

 更新時(shí)間:2021年11月14日 08:57:50   作者:老農(nóng)小江  
本文主要介紹了Java使用JMH進(jìn)行基準(zhǔn)性能測(cè)試,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下

一、前言

在日常開發(fā)工作當(dāng)中,開發(fā)人員可能有這些困惑:自己寫的這個(gè)方法性能到底怎么樣?在原接口實(shí)現(xiàn)方法中添加了新的業(yè)務(wù)邏輯,對(duì)整個(gè)接口的性能影響有多少?有多種實(shí)現(xiàn)方式(或開源類庫(kù)),到底哪一種性能更好?…
當(dāng)遇到類似困惑或者說問題的時(shí)候,怎么辦呢?當(dāng)然是測(cè)試驗(yàn)證,實(shí)踐出真知!本文講述的就是一個(gè)方法級(jí)別的性能測(cè)試工具——JMH。

二、JMH概述

1、什么是JMH

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

2、JMH適用的典型場(chǎng)景

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

3、JMH基本概念

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

三、JMH的使用

1、快速跑起來

  JMH的基本使用只需2步,第1步是引入maven依賴包,第2步是根據(jù)工具框架模板編寫測(cè)試類,以下通過一個(gè)簡(jiǎn)單例子進(jìn)行詳細(xì)說明:

例1:測(cè)試一個(gè)方法的平均耗時(shí)

第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步:編寫測(cè)試方法:

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使用第一個(gè)例子
 * @ 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();
    }
    /**
     * 測(cè)試sayHello的平局耗時(shí)
     *
     * @throws Exception
     */
    @Benchmark
    public void sayHello() throws Exception{
        //TODO 業(yè)務(wù)方法 ,此處用休眠的方式模擬業(yè)務(wù)耗時(shí)10 ms
        TimeUnit.MILLISECONDS.sleep(10);
    }
}

代碼說明:

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

直接運(yùn)行測(cè)試方法,控制臺(tái)輸出測(cè)試結(jié)果如下:(筆者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

測(cè)試結(jié)果說明:
整個(gè)測(cè)試結(jié)果分為3大塊,測(cè)試基本參數(shù)信息、測(cè)試過程、測(cè)試結(jié)果,各行含義具體說明如下:

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

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

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

2、JMH常用注解詳細(xì)介紹

注解 介紹
@BenchmarkMode 基準(zhǔn)測(cè)試模式。一共有5種可選值:(其實(shí)是4種)
Mode.Throughput:吞吐量模式,即單位時(shí)間內(nèi)方法的吞吐量
Mode.AverageTime:平均耗時(shí)模式,即一定測(cè)試次數(shù)內(nèi)方法執(zhí)行的平均耗時(shí)
Mode.SampleTime:隨機(jī)采樣模式,即最終結(jié)果為取樣結(jié)果分布比例
Mode.SingleShotTime:?jiǎn)未螆?zhí)行模式,即只會(huì)執(zhí)行一次(以上的模式通常會(huì)有預(yù)熱、會(huì)迭代執(zhí)行多次,這個(gè)模式可用于測(cè)試某些特定場(chǎng)景,如冷啟動(dòng)時(shí)的性能)
Mode.All:即以上模式都執(zhí)行一遍

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

------------------------------------
用法示例:(benchmark結(jié)果時(shí)間單位為毫秒)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@Benchmark 基準(zhǔn)測(cè)試,方法級(jí)注解(配置在方法名上)。用于標(biāo)注需要進(jìn)行benchmark (基準(zhǔn)測(cè)試)的方法

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

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

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

------------------------------------
用法示例:(使用3個(gè)進(jìn)程)
@Fork(3)
@Threads 線程數(shù)。每個(gè)Fork(進(jìn)程)中的線程數(shù),一般可設(shè)為測(cè)試機(jī)器cpu核心數(shù)。

------------------------------------
用法示例:(使用4個(gè)線程)
@Threads(4)
@Param 成員參數(shù),屬性級(jí)注解。用于測(cè)試方法在不同入?yún)⑶闆r下的性能表現(xiàn)。

------------------------------------
用法示例:(入?yún)⒅狄来螢? 、10、100)
@Param({“1”, “10”, “100”})
@Setup 設(shè)置,方法級(jí)注解。用于標(biāo)注benchmark前的操作,通常用于測(cè)試前初始化參數(shù)資源,如初始化數(shù)據(jù)庫(kù)連接等。

------------------------------------
用法示例:(初始化方法)
@Setup
@TearDown 拆卸,方法級(jí)注解。用于標(biāo)注benchmark后的操作,通常用于測(cè)試后回收資源,如關(guān)閉數(shù)據(jù)庫(kù)連接等。

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

------------------------------------
用法示例:(默認(rèn)值,每個(gè)線程分配一個(gè)實(shí)例)
@State(Scope.Thread)
@Group 測(cè)試組,方法級(jí)注解。適用分組測(cè)試,每組線程數(shù)不一樣的場(chǎng)景。

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

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

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

以上是使用JMH測(cè)試中常用的注解,當(dāng)然JMH還有一些其它注解,如@CompilerControl、@AuxCounters 等等,這些注解通??捎糜跐M足特定的測(cè)試場(chǎng)景需求,具體相關(guān)使用如有需要,可參考官方示例,官方demo比較詳細(xì),比較好理解學(xué)習(xí)。

3、更多示例

本小節(jié)筆者將通過幾個(gè)小示例,展示JMH的基本使用。
例2:
測(cè)試驗(yàn)證字符串連接處理時(shí),使用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使用第二個(gè)例子
 * @ 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();
    }
    /**
     * 字符串個(gè)數(shù)
     */
    @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);
        }
    }
}

測(cè)試結(jié)果:

//---省略測(cè)試過程結(jié)果----------
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

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

例3:
測(cè)試常用序列化json庫(kù)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使用第三個(gè)例子
 * @ 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();
    }
    /**
     * 序列化次數(shù)
     */
    @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);
        }
    }
    /**
     * 初始化參數(shù)
     */
    @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("北京三里屯兒那條街那條巷那一號(hào)");
        list.add("上海三里屯兒那條街那條巷那一號(hào)");
        list.add("深圳三里屯兒那條街那條巷那一號(hào)");
        userinfo.setAddress(list);
        
        fastjson_jsonStr = JsonUtil.fastjson_bean2Json(userinfo);
        gson_jsonStr = JsonUtil.gson_bean2Json(userinfo);
        jackson_jsonStr = JsonUtil.jackson_bean2Json(userinfo);
    }
}

(其它相關(guān)代碼后附)

測(cè)試結(jié)果:

//---省略測(cè)試過程結(jié)果----------
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

從測(cè)試結(jié)果可以看出,不論是bean2Json還是json2Bean,fastjson的性能比gson、jackson都要好一些,當(dāng)然,jackson性能也很不錯(cuò)(不愧是spring默認(rèn)的序列化和反序列化工具),尤其是當(dāng)序列化與反序列化次數(shù)較多時(shí),fastjson優(yōu)勢(shì)尤其明顯。當(dāng)然,由于筆者用于測(cè)試的實(shí)體bean數(shù)據(jù)結(jié)構(gòu)還是較為簡(jiǎn)單,在一些較為復(fù)雜的數(shù)據(jù)結(jié)構(gòu)場(chǎng)景下,其各自的性能表現(xiàn)可能有所不一樣。(筆者用的測(cè)試Mode是Mode.SingleShotTime,只測(cè)試一次,且由于機(jī)器等原因,所以誤差可能相對(duì)較大。有興趣的讀者,可以測(cè)試一下不同測(cè)試Mode下,更復(fù)雜的數(shù)據(jù)結(jié)構(gòu)場(chǎng)景下,各序列化/反序列化工具的性能表現(xiàn))

四、小結(jié)

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

    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;
    }
}

到此這篇關(guān)于詳解Java使用JMH進(jìn)行基準(zhǔn)性能測(cè)試的文章就介紹到這了,更多相關(guān)Java 基準(zhǔn)性能測(cè)試內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解java各種集合的線程安全

    詳解java各種集合的線程安全

    這篇文章主要介紹了詳解java各種集合的線程安全,小編覺得挺不錯(cuò)的,這里分享給大家,供需要的朋友參考。
    2017-10-10
  • Java實(shí)現(xiàn)簡(jiǎn)易GUI貪吃蛇小游戲

    Java實(shí)現(xiàn)簡(jiǎn)易GUI貪吃蛇小游戲

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)簡(jiǎn)易GUI貪吃蛇小游戲,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09
  • 簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理

    簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理

    這篇文章主要介紹了簡(jiǎn)單了解Spring Web相關(guān)模塊運(yùn)行原理,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-06-06
  • Spring?Boot各類變量的使用小結(jié)

    Spring?Boot各類變量的使用小結(jié)

    這篇文章主要介紹了Spring?Boot各類變量的使用小結(jié),本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2024-01-01
  • 詳解 Java 中 equals 和 == 的區(qū)別

    詳解 Java 中 equals 和 == 的區(qū)別

    這篇文章主要介紹了詳解 Java 中 equals 和 == 的區(qū)別的相關(guān)資料,equals 和 == 都是用來檢測(cè)兩個(gè)字符串是否相等,返回值也都是布爾型,但是兩者在內(nèi)部比較的處理中卻不盡相同需要的朋友可以參考下
    2017-03-03
  • Java實(shí)現(xiàn)連連看算法

    Java實(shí)現(xiàn)連連看算法

    這篇文章主要為大家詳細(xì)介紹了Java實(shí)現(xiàn)連連看算法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • springboot自動(dòng)配置沒有生效的問題定位(條件斷點(diǎn))

    springboot自動(dòng)配置沒有生效的問題定位(條件斷點(diǎn))

    這篇文章主要介紹了springboot自動(dòng)配置未生效問題定位,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,下面我們來學(xué)習(xí)一下吧
    2019-06-06
  • 在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程)

    在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程)

    這篇文章主要介紹了在eclipse中使用SVN的實(shí)現(xiàn)方法(圖文教程),文中通過圖文介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-07-07
  • javaDSL簡(jiǎn)單實(shí)現(xiàn)示例分享

    javaDSL簡(jiǎn)單實(shí)現(xiàn)示例分享

    DSL領(lǐng)域定義語(yǔ)言,用來描述特定領(lǐng)域的特定表達(dá)。比如畫圖從起點(diǎn)到終點(diǎn);路由中的從A到B。這是關(guān)于畫圖的一個(gè)簡(jiǎn)單實(shí)現(xiàn)
    2014-03-03
  • 新手小白學(xué)JAVA 日期類Date SimpleDateFormat Calendar(入門)

    新手小白學(xué)JAVA 日期類Date SimpleDateFormat Calendar(入門)

    本文主要介紹了JAVA 日期類Date SimpleDateFormat Calendar,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-10-10

最新評(píng)論