大家好,又见面了,我是你们的朋友全栈君。
一 什么是 JMH
JMH 是在 method 层面上的 benchmark,精度可以精确到微秒级,是对热点函数进行优化时,对优化结果进行定量分析的工具。
二 JMH 的应用场景
典型场景:
- 想定量地知道某个函数需要执行多长时间,以及执行时间和输入 n 的相关性。
- 一个函数有多种不同的实现,针对多种不同的实现,需要定量分析出那种实现性能更好。
三 JMH 的使用
3.1 引入依赖
代码语言:javascript复制<dependencies>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-core</artifactId>
<version>1.14.1</version>
</dependency>
<dependency>
<groupId>org.openjdk.jmh</groupId>
<artifactId>jmh-generator-annprocess</artifactId>
<version>1.14.1</version>
<scope>provided</scope>
</dependency>
</dependencies>
3.2 使用介绍
下面样例是比较一下 AtomicLong 和 LongAdder 的性能:
代码语言:javascript复制package com.sb.springbootjmh;
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;
import java.util.concurrent.atomic.AtomicLong;
import java.util.concurrent.atomic.LongAdder;
@OutputTimeUnit(TimeUnit.MICROSECONDS)
@BenchmarkMode(Mode.Throughput)
@State(Scope.Thread)
public class Main {
private static AtomicLong count = new AtomicLong();
private static LongAdder longAdder = new LongAdder();
public static void main(String[] args) throws Exception {
Options options = new OptionsBuilder()
.include(Main.class.getName())
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build();
new Runner(options).run();
}
@Benchmark
@Threads(10)
public void run0(){
count.getAndIncrement();
}
@Benchmark
@Threads(10)
public void run1(){
longAdder.increment();
}
}
得到如下结果:
3.3 JMH注解说明
@Benchmark
表示该方法是需要进行 benchmark 的对象,用法和 JUnit 的 @Test
类似。其中 Mode 有四种选择:
Throughput
: 整体吞吐量,例如“1秒内可以执行多少次调用”。AverageTime
: 调用的平均时间,例如“每次调用平均耗时xxx毫秒”。SampleTime
: 随机取样,最后输出取样结果的分布,例如“99%的调用在xxx毫秒以内,99.99%的调用在xxx毫秒以内”SingleShotTime
: 以上模式都是默认一次 iteration 是 1s,唯有SingleShotTime
是只运行一次。往往同时把 warmup 次数设为0,用于测试冷启动时的性能。
@State
State
用于声明某个类是一个“状态”,然后接受一个 Scope
参数用来表示该状态的共享范围。因为很多 benchmark 会需要一些表示状态的类,JMH 允许你把这些类以依赖注入的方式注入到 benchmark 函数里。Scope
主要分为两种。
Thread
: 该状态为每个线程独享。Benchmark
: 该状态在所有线程间共享。
@OutputTimeUnit
benchmark 结果所使用的时间单位。
3.4 JMH 启动参数说明
代码语言:javascript复制Options options = new OptionsBuilder()
.include(Main.class.getName())
.forks(1)
.warmupIterations(5)
.measurementIterations(5)
.build();
- include
benchmark 所在的类的名字,注意这里是使用正则表达式对所有类进行匹配的。
- fork
进行 fork 的次数。如果 fork 数是2的话,则 JMH 会 fork 出两个进程来进行测试。
- warmupIterations
预热的迭代次数。
- measurementIterations
实际测量的迭代次数。
四 参考说明
本文只是简单的介绍 JMH 的使用,要想深入了解请参考如下链接:
官网:http://hg.openjdk.java.net/code-tools/jmh/file/tip/jmh-samples/src/main/java/org/openjdk/jmh/samples/
https://blog.dyngr.com/blog/2016/10/29/introduction-of-jmh/
https://www.jianshu.com/p/67a75e36166f
发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/157389.html原文链接:https://javaforall.cn