顶级Java才懂的,基准测试JMH

本文介绍了如何使用Java Microbenchmark Harness (JMH) 进行性能基准测试,讲解了关键注解如@Warmup、@Measurement、@BenchmarkMode等的用途,强调了预热和性能指标的重要性,并展示了JMH如何帮助优化和比较ID生成器的性能。通过JMH,开发者可以更精确地评估代码性能,提高代码质量。
摘要由CSDN通过智能技术生成

最近在手写一个ID生成器,需要比较UUID和目前比较流行的 NanoID之间的速度差异,当然也要测一下根据规则自创的ID生成器。

这样的代码属于最基础的API,速度哪怕减上几纳秒,累加起来也是很可观的。关键是,我该如何评估ID的生成速度呢?

1. 如何统计性能?

常见的方法,是写一些统计代码。这些代码,穿插在我们的逻辑中,进行一些简单的计时运算。比如下面这几行:

long start = System.currentTimeMillis();
//logic
long cost = System.currentTimeMillis() - start;
System.out.println("Logic cost : " + cost);
复制代码

这样的统计方式,用在业务代码里,哪怕是APM里,并不见得有什么问题。

可惜的是,这段代码的统计结果,并不见得一定准确。举个例子来说,JVM在执行时,会对一些代码块,或者一些频繁执行的逻辑,进行JIT编译和内联优化,在得到一个稳定的测试结果之前,需要先循环上上万次,进行预热。预热前和预热后的性能差别是非常大的。

另外,评估性能,有很多的指标。如果这些指标数据,每次都要手工去算的话,那肯定是枯燥乏味且低效的。

JMH(the Java Microbenchmark Harness) 就是这样一个能够做基准测试的工具。如果你通过我们一系列的工具,定位到了热点代码,要测试它的性能数据,评估改善情况,就可以交给JMH。它的测量精度非常高,最高可达到纳秒的级别。

JMH已经在JDK 12中被包含,其他版本的需要自行引入maven,坐标如下。

<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>
            <scope>provided</scope>
        </dependency>
    </dependencies>
复制代码

下面,我们介绍一下这个工具的使用。

2. 关键注解

JMH是一个jar包,它和单元测试框架JUnit非常的像,可以通过注解进行一些基础配置。这部分配置有很多是可以通过main方法的OptionsBuilder进行设置的。

image.png

上图是一个典型的JMH程序执行的内容。通过开启多个进程,多个线程,首先执行预热,然后执行迭代,最后汇总所有的测试数据进行分析。在执行前后,还可以根据粒度处理一些前置和后置操作。

一个简单的代码如下:

@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 BenchmarkTest {
    @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 = 455565655225562L;
        long a = 0;
        for (int i = 0; i < 1000; i++) {
            a = t / 1
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值