亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java JMH進(jìn)行基準(zhǔn)測(cè)試的使用小結(jié)

 更新時(shí)間:2025年05月07日 09:32:49   作者:終點(diǎn)就在前方  
在 Java 的依賴庫(kù)中,有個(gè)大名鼎鼎的 JMH(Java Microbenchmark Harness),是由 Java虛擬機(jī)團(tuán)隊(duì)開發(fā)的 Java 基準(zhǔn)測(cè)試工具,下面小編來和大家講講它的具體使用吧

在 Java 的依賴庫(kù)中,有個(gè)大名鼎鼎的 JMH(Java Microbenchmark Harness),是由 Java虛擬機(jī)團(tuán)隊(duì)開發(fā)的 Java 基準(zhǔn)測(cè)試工具。

在 JMH 中,正如 單元測(cè)試框架 JUnit 一樣,我們也可以通過大量的注解來進(jìn)行一定的配置,一個(gè)典型的 JMH 程序執(zhí)行如下圖所示[2]:

也即,通過開啟多個(gè)進(jìn)程,多個(gè)線程,先執(zhí)行預(yù)熱,然后執(zhí)行迭代,最后匯總所有的測(cè)試數(shù)據(jù)進(jìn)行分析,這就是 JMH 的執(zhí)行流程,聽起來是不是不難理解。

1.示例

學(xué)習(xí)新技能通常先通過一個(gè) case 來幫準(zhǔn)我們?cè)趺从?,有什么結(jié)果,這里我們通過改寫官方的一個(gè) sample 來看看。

package org.example;
 
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Measurement;
import org.openjdk.jmh.annotations.Warmup;
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;
 
@Warmup(iterations = 1, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 2, time = 1, timeUnit = TimeUnit.SECONDS)
public class HelloWorldBenchmark {
    private static int num = 0;
    @Benchmark
    public void helloWorld() {
        ++num;
    }
 
 
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder()
                .include(HelloWorldBenchmark.class.getSimpleName())
                .forks(1)
                .result("helloWorld.json")
                .resultFormat(ResultFormatType.JSON)
                .build();
 
        new Runner(opt).run();
    }
}

示例很簡(jiǎn)單,就是簡(jiǎn)單對(duì) static 變量做自增,最后將結(jié)果輸出到 json 文件中,下面是運(yùn)行結(jié)果:

# JMH version: 1.23
# VM version: JDK 21, Java HotSpot(TM) 64-Bit Server VM, 21+35-LTS-2513
# VM invoker: C:\Program Files\Java\jdk-21\bin\java.exe
# VM options: -javaagent:D:\chromedownload\ideaIC-2023.2.3.win\lib\idea_rt.jar=55507:D:\chromedownload\ideaIC-2023.2.3.win\bin -Dfile.encoding=UTF-8 -Dsun.stdout.encoding=UTF-8 -Dsun.stderr.encoding=UTF-8
# Warmup: 1 iterations, 1 s each
# Measurement: 2 iterations, 1 s each
# Timeout: 10 min per iteration
# Threads: 1 thread, will synchronize iterations
# Benchmark mode: Throughput, ops/time
# Benchmark: org.example.HelloWorldBenchmark.helloWorld
 
# Run progress: 0.00% complete, ETA 00:00:03
# Fork: 1 of 1
# Warmup Iteration   1: 1659899825.872 ops/s
Iteration   1: 1646745186.884 ops/s
Iteration   2: 1681125023.980 ops/s
 
 
Result "org.example.HelloWorldBenchmark.helloWorld":
  1663935105.432 ops/s
 
 
# Run complete. Total time: 00:00:03
 
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
HelloWorldBenchmark.helloWorld  thrpt    2  1663935105.432          ops/s
 
Benchmark result is saved to helloWorld.json

通過簡(jiǎn)單的設(shè)置,我們?cè)诨鶞?zhǔn)測(cè)試中可以看到多次測(cè)試的每秒吞吐量,最后結(jié)果輸出到 helloWorldjson 文件:

[
    {
        "jmhVersion" : "1.23",
        "benchmark" : "org.example.HelloWorldBenchmark.helloWorld",
        "mode" : "thrpt",
        "threads" : 1,
        "forks" : 1,
        "jvm" : "C:\Program Files\Java\jdk-21\bin\java.exe",
        "jvmArgs" : [
            "-javaagent:D:\chromedownload\ideaIC-2023.2.3.win\lib\idea_rt.jar=55507:D:\chromedownload\ideaIC-2023.2.3.win\bin",
            "-Dfile.encoding=UTF-8",
            "-Dsun.stdout.encoding=UTF-8",
            "-Dsun.stderr.encoding=UTF-8"
        ],
        "jdkVersion" : "21",
        "vmName" : "Java HotSpot(TM) 64-Bit Server VM",
        "vmVersion" : "21+35-LTS-2513",
        "warmupIterations" : 1,
        "warmupTime" : "1 s",
        "warmupBatchSize" : 1,
        "measurementIterations" : 2,
        "measurementTime" : "1 s",
        "measurementBatchSize" : 1,
        "primaryMetric" : {
            "score" : 1.6639351054317546E9,
            "scoreError" : "NaN",
            "scoreConfidence" : [
                "NaN",
                "NaN"
            ],
            "scorePercentiles" : {
                "0.0" : 1.6467451868835843E9,
                "50.0" : 1.6639351054317546E9,
                "90.0" : 1.6811250239799252E9,
                "95.0" : 1.6811250239799252E9,
                "99.0" : 1.6811250239799252E9,
                "99.9" : 1.6811250239799252E9,
                "99.99" : 1.6811250239799252E9,
                "99.999" : 1.6811250239799252E9,
                "99.9999" : 1.6811250239799252E9,
                "100.0" : 1.6811250239799252E9
            },
            "scoreUnit" : "ops/s",
            "rawData" : [
                [
                    1.6467451868835843E9,
                    1.6811250239799252E9
                ]
            ]
        },
        "secondaryMetrics" : {
        }
    }
]

看完怎么用,接下來看看在項(xiàng)目中注意的點(diǎn)和值得注意的參數(shù)注解。

2.JMH的使用

引入依賴

由于這不是標(biāo)準(zhǔn)庫(kù)有的依賴,所以這里我們依然用 Maven 管理依賴,在我們構(gòu)建的 Maven 項(xiàng)目中的 pom.xml 添加下列依賴:

<dependencies>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-core</artifactId>
        <version>1.23</version>
    </dependency>
    <dependency>
        <groupId>org.openjdk.jmh</groupId>
        <artifactId>jmh-generator-annprocess</artifactId>
        <version>1.23</version>
    </dependency>

接下來看看代碼應(yīng)用。

代碼示例基于參考編寫:

package org.example;
 
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)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
 
@State(Scope.Thread)
@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)
@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)
 
@Fork(1)
@Threads(2)
public class MyBenchmarkTest {
    @Benchmark
    public long shift() {
        long t = 455565655225562L;
        long a = 0;
        for (int i = 0; i < 1000; i++) {
            a = t >> 30;
        }
        return a;
    }
 
    @Benchmark
    public long div() {
        long t = Long.MAX_VALUE;
        long a = 0;
        for (int i = 0; i < 1000; i++) {
            a = t / 1024 / 1024 / 1024;
        }
 
        return a;
    }
 
    public static void main(String[] args) throws RunnerException {
        Options opts = new OptionsBuilder()
                .include(MyBenchmarkTest.class.getSimpleName())
                .result("MyBenchmarkTest.json")
                .resultFormat(ResultFormatType.JSON)
                .build();
 
        new Runner(opts).run();
    }
}

在示例中,其實(shí)我們的目的就是測(cè)試 移位和整除 兩個(gè)方法的性能,看看每秒的吞吐量如何,最后將結(jié)果匯總在 MyBenchmarkTest.json 文件中,當(dāng)然運(yùn)行測(cè)試,我們也可以在控制臺(tái)得到相應(yīng)輸出。

注解

在上面的 demo 中,我們?cè)陬惿霞恿撕芏嘧⒔?,注解的作用又是啥呢?/p>

@BenchmarkMode

該注解用來指定基準(zhǔn)測(cè)試類型,對(duì)應(yīng) Mode 選項(xiàng),修飾類和方法,這里我們修飾類,注解的 value 是 Mode[] 類型,我們這里填入的是 Throughput ,表示整體吞吐量,即單位時(shí)間內(nèi)的調(diào)用量,查看 Mode 源碼就可以發(fā)現(xiàn),其實(shí)總的類型有以下:

  • Throughput: 略

  • AverageTime: 平均耗時(shí),指的是每次執(zhí)行的平均時(shí)間。如果這個(gè)值很小不好辨認(rèn),可以把統(tǒng)計(jì)的單位時(shí)間調(diào)小一點(diǎn)。

  • SampleTime: 隨機(jī)取樣。

  • SingleShotTime: 如果你想要測(cè)試僅僅一次的性能,比如第一次初始化花了多長(zhǎng)時(shí)間,就可以使用這個(gè)參數(shù),其實(shí)和傳統(tǒng)的main方法沒有什么區(qū)別。

  • All: 所有的指標(biāo),都算一遍。

從 控制臺(tái)的結(jié)果可以看看相關(guān)輸出:

Benchmark               Mode  Cnt       Score      Error   Units
MyBenchmarkTest.div    thrpt    5  500758.115 ± 3350.796  ops/ms
MyBenchmarkTest.shift  thrpt    5  500045.811 ± 1609.779  ops/ms

如果填入 Mode.All 看看結(jié)果輸出:

Benchmark                              Mode     Cnt       Score      Error   Units
MyBenchmarkTest.div                   thrpt       5  500554.176 ± 8015.731  ops/ms
MyBenchmarkTest.shift                 thrpt       5  499731.423 ± 4635.160  ops/ms
MyBenchmarkTest.div                    avgt       5      ≈ 10??              ms/op
MyBenchmarkTest.shift                  avgt       5      ≈ 10??              ms/op
MyBenchmarkTest.div                  sample  316909      ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.00        sample                 ≈ 0              ms/op
MyBenchmarkTest.div:div·p0.50        sample                 ≈ 0              ms/op
MyBenchmarkTest.div:div·p0.90        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.95        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.99        sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.999       sample              ≈ 10??              ms/op
MyBenchmarkTest.div:div·p0.9999      sample               0.002              ms/op
MyBenchmarkTest.div:div·p1.00        sample               0.025              ms/op
MyBenchmarkTest.shift                sample  315964      ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.00    sample                 ≈ 0              ms/op
MyBenchmarkTest.shift:shift·p0.50    sample                 ≈ 0              ms/op
MyBenchmarkTest.shift:shift·p0.90    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.95    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.99    sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.999   sample              ≈ 10??              ms/op
MyBenchmarkTest.shift:shift·p0.9999  sample               0.001              ms/op
MyBenchmarkTest.shift:shift·p1.00    sample               0.024              ms/op
MyBenchmarkTest.div                      ss       5       0.052 ±    0.091   ms/op
MyBenchmarkTest.shift                    ss       5       0.015 ±    0.023   ms/op

此時(shí)可以看到十分詳盡的輸出,每秒的吞吐量,每個(gè)操作的耗費(fèi)時(shí)間等,因?yàn)楸纠?jiǎn)單,時(shí)間耗費(fèi)建議填入 ns 等單位。

@BenchmarkMode 表示單位時(shí)間的操作數(shù)或者吞吐量,或者每個(gè)操作耗費(fèi)的時(shí)間等,注意我們都沒有限定時(shí)間單位,所以通常這個(gè)注解也會(huì)和 @OutputTimeUnit 結(jié)合使用。

@OutputTimeUnit

基準(zhǔn)測(cè)試結(jié)果的時(shí)間類型。一般選擇秒、毫秒、微秒,這里填入的是 TimeUnit 這個(gè)枚舉類型,涉及單位很多從納秒到天都有,按需選擇,最終輸出易讀的結(jié)果。

@State

@State 指定了在類中變量的作用范圍。它有三個(gè)取值。

@State 用于聲明某個(gè)類是一個(gè)“狀態(tài)”,可以用Scope 參數(shù)用來表示該狀態(tài)的共享范圍。這個(gè)注解必須加在類上,否則提示無法運(yùn)行。

Scope有如下3種值:

  • Benchmark:表示變量的作用范圍是某個(gè)基準(zhǔn)測(cè)試類。
  • Thread:每個(gè)線程一份副本,如果配置了Threads注解,則每個(gè)Thread都擁有一份變量,它們互不影響。
  • Group:聯(lián)系上面的@Group注解,在同一個(gè)Group里,將會(huì)共享同一個(gè)變量實(shí)例。

本例中,相關(guān)變量的作用范圍是 Thread。

@Warmup

預(yù)熱,可以加在類上或者方法上,預(yù)熱只是測(cè)試數(shù)據(jù),是不作為測(cè)量結(jié)果的。

該注解一共有4個(gè)參數(shù):

  • iterations 預(yù)熱階段的迭代數(shù)
  • time 每次預(yù)熱時(shí)間
  • timeUnit 時(shí)間單位,通常秒
  • batchSize 批處理大小,指定每次操作調(diào)用幾次方法

本例中,我們加在類上,讓它迭代3次,每次1秒,時(shí)間單位秒。

@Measurement

和預(yù)熱類似,這里的注解是會(huì)影響測(cè)試結(jié)果的,它的參數(shù)和 Warmup 一樣,這里不多介紹。

本例中我們?cè)诘性O(shè)置的是5次,每次1秒。

通常 @Warmup 和 @Measurement 兩個(gè)參數(shù)會(huì)一起使用。

@Fork

表示開啟幾個(gè)進(jìn)程測(cè)試,通常我們?cè)O(shè)為1,如果數(shù)值大于1,則啟用新的進(jìn)程測(cè)試,如果設(shè)置為0,程序依然進(jìn)行,但是在用戶的 JVM 進(jìn)程上運(yùn)行。

追蹤一下JMH的源碼,發(fā)現(xiàn)每個(gè)fork進(jìn)程是單獨(dú)運(yùn)行在Proccess進(jìn)程里的,這樣就可以做完全的環(huán)境隔離,避免交叉影響。它的輸入輸出流,通過Socket連接的模式,發(fā)送到我們的執(zhí)行終端。

如果需要更多的設(shè)置,可以看看 Fork.class 源碼,上面還有 jvm 參數(shù)設(shè)置。

@Threads

上面的注解注重開啟幾個(gè)進(jìn)程,這里就是開啟幾個(gè)線程,只有一個(gè)參數(shù) value,指定注解的value,將會(huì)開啟并行測(cè)試,如果設(shè)置的 value 過大,如 Threads.Max,則使用處理機(jī)的相同線程數(shù)。

@Benchmark

加在測(cè)試方法上,表示該方法是需要進(jìn)行基準(zhǔn)測(cè)試的,類似 JUnit5 中的 @Test 注解需要單元測(cè)試的方法一樣。

@Setup

注解的作用就是我們需要在測(cè)試之前進(jìn)行一些準(zhǔn)備工作,比如對(duì)一些數(shù)據(jù)的初始化之類的,這個(gè)也和Junit的@Before

@Teardown

在測(cè)試之后進(jìn)行一些結(jié)束工作,主要用于資源回收

開啟測(cè)試

上述的學(xué)習(xí)中主要是相關(guān)注解,這里看看具體我們?cè)趺从谩?/p>

public static void main(String[] args) throws RunnerException {
    Options opts = new OptionsBuilder()
            // 表示包含的測(cè)試類
            .include(MyBenchmarkTest.class.getSimpleName()) 
            // 最后結(jié)果輸出文件的命名
            .result("MyBenchmarkTest.json")
            // 結(jié)果輸出什么格式,可以是json, csv, text等
            .resultFormat(ResultFormatType.JSON)
            .build();
 
    new Runner(opts).run(); // 運(yùn)行
}

3.JMH可視化

作為程序開發(fā)人員,看懂測(cè)試結(jié)果沒難度,測(cè)試結(jié)果文本能可視化更好。

好在我們拿到了JMH 結(jié)果后,根據(jù)文件格式,我們可以二次加工,就可以圖表化展示[2]。

JMH 支持的幾種輸出格式:

  • TEXT 導(dǎo)出文本文件。
  • CSV 導(dǎo)出csv格式文件。
  • SCSV 導(dǎo)出scsv等格式的文件。
  • JSON 導(dǎo)出成json文件。
  • LATEX 導(dǎo)出到latex,一種基于ΤΕΧ的排版系統(tǒng)。

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

相關(guān)文章

  • Spring Cache原理解析

    Spring Cache原理解析

    Spring Cache是一個(gè)框架,它提供了基于注解的緩存功能,使得開發(fā)者可以很方便地將緩存集成到他們的應(yīng)用程序中,這篇文章主要介紹了Spring Cache原理解析,需要的朋友可以參考下
    2024-05-05
  • 聊聊Lombok中的@Builder注解使用教程

    聊聊Lombok中的@Builder注解使用教程

    @Builder注解的作用主要是用來生成對(duì)象,并且可以為對(duì)象鏈?zhǔn)劫x值。接下來通過本文給大家介紹Lombok中的@Builder注解使用教程,感興趣的朋友一起看看吧
    2021-11-11
  • Java中的HashSet、LinkedHashSet集合解析

    Java中的HashSet、LinkedHashSet集合解析

    這篇文章主要介紹了Java中的HashSet、LinkedHashSet集合解析,與HashSet不同的是,LinkedHashSet在內(nèi)部使用了一個(gè)雙向鏈表來維護(hù)元素的順序,因此它可以保持元素的插入順序,這使得LinkedHashSet在需要保持元素順序的場(chǎng)景下非常有用,需要的朋友可以參考下
    2023-11-11
  • java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例

    java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例

    今天小編就為大家分享一篇java調(diào)用shell命令并獲取執(zhí)行結(jié)果的示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2018-07-07
  • MyBatis中的模糊查詢語句

    MyBatis中的模糊查詢語句

    這篇文章主要介紹了MyBatis中的模糊查詢語句的相關(guān)資料,需要的朋友可以參考下
    2017-03-03
  • 詳解Spring全局異常處理的三種方式

    詳解Spring全局異常處理的三種方式

    這篇文章主要介紹了詳解Spring全局異常處理的三種方式,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-04-04
  • java使用EasyExcel導(dǎo)入導(dǎo)出excel

    java使用EasyExcel導(dǎo)入導(dǎo)出excel

    導(dǎo)入導(dǎo)出excel數(shù)據(jù)是常見的需求,今天就來看一下Java基于EasyExcel實(shí)現(xiàn)這個(gè)功能,感興趣的朋友可以了解下
    2021-05-05
  • SpringBoot?2.x整合Log4j2日志的詳細(xì)步驟

    SpringBoot?2.x整合Log4j2日志的詳細(xì)步驟

    log4j2優(yōu)越的性能其原因在于log4j2使用了LMAX,一個(gè)無鎖的線程間通信庫(kù)代替了,logback和log4j之前的隊(duì)列,并發(fā)性能大大提升,下面這篇文章主要給大家介紹了關(guān)于SpringBoot?2.x整合Log4j2日志的相關(guān)資料,需要的朋友可以參考下
    2022-10-10
  • 如何導(dǎo)入spring源碼到IDEA

    如何導(dǎo)入spring源碼到IDEA

    這篇文章主要介紹了如何導(dǎo)入spring源碼到IDEA,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • 解析Java的Spring框架的基本結(jié)構(gòu)

    解析Java的Spring框架的基本結(jié)構(gòu)

    這篇文章主要介紹了Java的Spring框架的基本結(jié)構(gòu),作者從Spring的設(shè)計(jì)角度觸發(fā)解析其基礎(chǔ)的架構(gòu)內(nèi)容,需要的朋友可以參考下
    2016-03-03

最新評(píng)論