Java性能测试Benchmark使用总结

如何测量Java代码的性能

在 Java 中,可以使用多种方法来测量一段代码的执行性能。使用 System.currentTimeMillis()是最常见的方法

long startTime = System.currentTimeMillis();// 需要测量的代码块
for (int i = 0; i < 1000000; i++) {// 示例代码
}long endTime = System.currentTimeMillis();
long duration = endTime - startTime; // 执行时间(毫秒)
System.out.println("Execution time: " + duration + " ms");

但是这么测结果是不太准确的,因为Java存在代码优化以及JIT编译等等,通常更准确的方式是使用Benchmark的方式来评估性能。

JMH基本使用

参考:https://github.com/openjdk/jmh
Java Microbenchmark Harness (JMH) 是一个用于基准测试 Java 代码的工具。它能够准确测量代码的性能,帮助开发者了解不同实现的效率。

首先添加依赖,jmh一般用于test,所以scope可以指定为test

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

示例如下:

package org.example;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.Arrays;
import java.util.concurrent.TimeUnit;@BenchmarkMode(Mode.AverageTime)
@OutputTimeUnit(TimeUnit.MILLISECONDS)
@State(Scope.Benchmark)
public class JMHExample {private int[] numbers;public static void main(String[] args) throws Exception {Options opts = new OptionsBuilder().include(JMHExample.class.getSimpleName()) // 指定测试的类.build();new Runner(opts).run();  // 运行}@Setup(Level.Trial)public void setup() {numbers = new int[1000];for (int i = 0; i < numbers.length; i++) {numbers[i] = i;}}@Benchmarkpublic int sumArray() {int sum = 0;for (int number : numbers) {sum += number;}return sum;}@Benchmarkpublic int sumArrayParallel() {return Arrays.stream(numbers).parallel().sum();}
}

在示例中,其实我们的目的就是比较两种对数组求和方式的性能,看看每秒的吞吐量如何,运行测试,可以在控制台得到相应输出。

常用注解

@Benchmark

@Benchmark 注解是用于标记测试方法的,类似 JUnit 中的 @Test 注解需要单元测试的方法一样,只有被这个注解标记的方法才会参与基准测试,且被标记的方法必须是 public 的。在一个基本测试类中至少包含一个被 @Benchmark 标记的方法,否则会抛出异常。

@BenchmarkMode

@BenchmarkMode 注解用于指定基准测试的模式。JMH 共有四种模式:

  1. Throughput:整体吞吐量,例如“1 秒内可以执行多少次调用”。
  2. AverageTime:调用的平均时间,例如“每次调用平均耗时 xxx 毫秒”。如果需要测试某个方法的平均耗时,可以使用@BenchmarkMode 注解并指定基准测试的模式为 AverageTime。
  3. SampleTime:随机取样,最后输出取样结果的分布,例如“99%的调用在 xxx 毫秒以内,99.99%的调用在 xxx 毫秒以内”。
  4. SingleShotTime:以上模式都是默认一次 iteration 是 1s,唯有 SingleShotTime 是只运行一次。往往同时把 warmup 次数设为 0,用于测试冷启动时的性能。
  5. All:所有的指标全算一遍

在使用时,@BenchmarkMode 注解可设置在类上也可以设置在基准方法上。例如:

@Benchmark
@BenchmarkMode(Mode.AverageTime)
public void methodToTest() {// 测试代码
}

@OutputTimeUnit

基准测试结果的时间类型。一般选择秒、毫秒、微秒,这里填入的是 TimeUnit 这个枚举类型,涉及单位很多从纳秒到天都有,按需选择,最终输出易读的结果。

@State

@State 指定了在类中变量的作用范围。@State 用于声明某个类是一个“状态”,可以用Scope 参数用来表示该状态的共享范围。这个注解必须加在类上,否则提示无法运行。它有三个取值。

  1. Benchmark:表示变量的作用范围是某个基准测试类。
  2. Thread:每个线程一份副本,如果配置了Threads注解,则每个Thread都拥有一份变量,它们互不影响。
  3. Group:联系上面的@Group注解,在同一个Group里,将会共享同一个变量实例。

本例中,相关变量的作用范围是 Benchmark。

@Warmup

预热,可以加在类上或者方法上,预热只是测试数据,是不作为测量结果的。

该注解一共有4个参数:

  1. iterations 预热阶段的迭代数
  2. time 每次预热时间
  3. timeUnit 时间单位,通常秒
  4. batchSize 批处理大小,指定每次操作调用几次方法

本例中,我们加在类上,让它迭代3次,每次1秒,时间单位秒。

@Setup

注解的作用就是我们需要在测试之前进行一些准备工作,比如对一些数据的初始化之类的,这个也和Junit的@Before等类似

@Teardown

在测试之后进行一些结束工作,主要用于资源回收

@Measurement

和预热类似,这个注解是会影响测试结果的,它的参数和 Warmup 一样,这里不多介绍。
本例中我们在迭代中设置的是5次,每次1秒。
通常 @Warmup 和 @Measurement 两个参数会一起使用。

@Fork

表示开启几个进程测试,通常我们设为1,如果数值大于1,则启用新的进程测试,如果设置为0,程序依然进行,但是在用户的 JVM 进程上运行。

@Threads

上面的注解注重开启几个进程,这里就是开启几个线程,只有一个参数 value,指定注解的value,将会开启并行测试,如果设置的 value 过大,如 Threads.Max,则使用处理机的相同线程数。

输出格式

public static void main(String[] args) throws RunnerException {Options opts = new OptionsBuilder()// 表示包含的测试类.include(JMHExample.class.getSimpleName()) // 最后结果输出文件的命名,不指定默认为jmh-reuslt.json.result("benchmark.json")// 结果输出什么格式,可以是json, csv, text等.resultFormat(ResultFormatType.JSON).build();new Runner(opts).run(); // 运行
}

作为程序开发人员,看懂测试结果没难度,测试结果文本能可视化更好。好在我们拿到了JMH 结果后,根据文件格式,我们可以二次加工,就可以图表化展示[2]。

JMH 支持的几种输出格式:

  1. TEXT 导出文本文件。
  2. CSV 导出csv格式文件。
  3. SCSV 导出scsv等格式的文件。
  4. JSON 导出成json文件。
  5. LATEX 导出到latex,一种基于ΤΕΧ的排版系统。

比如 CSV 格式的文件,我们就可以通过 EXCEL 处理获取图表,当然也还有其他的一些工具,例如:

  1. https://jmh.morethan.io/,参考:https://github.com/jzillmann/jmh-visualizer
    在这里插入图片描述
    这个网站要使用json格式的输出结果
    在这里插入图片描述

jmh-generator

JMH生成测试代码的方式有多种,例如jmh-generator-annprocessjmh-generator-reflection 是 JMH(Java Microbenchmark Harness)中用于基准测试生成的两个核心组件。

  1. jmh-generator-annprocess:这个模块用于在编译时处理基准测试的注解。它通过注解处理器生成相应的基准测试代码。
  • 性能:由于是在编译时生成代码,运行时的开销较小,因此性能较好。

  • 类型安全:在编译时生成的代码是类型安全的,可以捕获潜在的错误。

使用场景:适合于需要大量基准测试并且希望在编译时进行优化的场景。

  1. jmh-generator-reflection:这个模块使用反射机制在运行时生成基准测试代码,在运行时读取类的结构,并生成相应的基准测试实现。
  • 优点

    • 灵活性:可以动态生成基准测试,适合那些在编译时无法确定的基准测试场景。
    • 简化:对于简单或快速的基准测试,开发者无需进行额外的编译配置。
  • 缺点

    • 性能开销:由于使用反射,运行时性能开销相对较大。
    • 类型安全:可能导致运行时错误,缺乏编译时检查。

如果需要高性能、类型安全的基准测试,并且可以接受编译时的复杂性。选择 jmh-generator-annprocess,如果希望动态生成基准测试,或者在快速原型开发时需要更灵活的解决方案。选择 jmh-generator-reflection

对应的maven依赖如下

参考:https://mvnrepository.com/artifact/org.openjdk.jmh

<!-- 基于注解处理器生成 -->
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-annprocess</artifactId><version>1.37</version><scope>test</scope>
</dependency>
<!-- 基于反射生成 -->
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-reflection</artifactId><version>1.37</version><scope>test</scope>
</dependency>
<!-- 基于字节码生成 -->
<dependency><groupId>org.openjdk.jmh</groupId><artifactId>jmh-generator-bytecode</artifactId><version>1.37</version><scope>test</scope>
</dependency>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/493627.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Win10将WindowsTerminal设置默认终端并添加到右键(无法使用微软商店)

由于公司内网限制&#xff0c;无法通过微软商店安装 Windows Terminal&#xff0c;本指南提供手动安装和配置新版 Windows Terminal 的步骤&#xff0c;并添加右键菜单快捷方式。 1. 下载新版终端安装包: 访问 Windows Terminal 的 GitHub 发布页面&#xff1a;https://githu…

Linux网络基础--传输层Tcp协议(上) (详细版)

目录 Tcp协议报头&#xff1a; 4位首部长度&#xff1a; 源端口号和目的端口号 32位序号和确认序号 标记位 超时重传机制&#xff1a; 两个问题 连接管理机制 三次握手&#xff0c;四次挥手 建立连接&#xff0c;为什么要有三次握手&#xff1f; 先科普一个概念&…

【NLP 18、新词发现和TF·IDF】

目录 一、新词发现 1.新词发现的衡量标准 ① 内部稳固 ② 外部多变 2.示例 ① 初始化类 NewWordDetect ② 加载语料信息&#xff0c;并进行统计 ③ 统计指定长度的词频及其左右邻居字符词频 ④ 计算熵 ⑤ 计算左右熵 ​编辑 ⑥ 统计词长总数 ⑦ 计算互信息 ⑧ 计算每个词…

clickhouse-数据库引擎

1、数据库引擎和表引擎 数据库引擎默认是Ordinary&#xff0c;在这种数据库下面的表可以是任意类型引擎。 生产环境中常用的表引擎是MergeTree系列&#xff0c;也是官方主推的引擎。 MergeTree是基础引擎&#xff0c;有主键索引、数据分区、数据副本、数据采样、删除和修改等功…

Pytorch | 从零构建Vgg对CIFAR10进行分类

Pytorch | 从零构建Vgg对CIFAR10进行分类 CIFAR10数据集Vgg网络结构特点性能应用影响 Vgg结构代码详解结构代码代码详解特征提取层 _make_layers前向传播 forward 训练过程和测试结果代码汇总vgg.pytrain.pytest.py 前面文章我们构建了AlexNet对CIFAR10进行分类&#xff1a; Py…

大数据机器学习算法和计算机视觉应用07:机器学习

Machine Learning Goal of Machine LearningLinear ClassificationSolutionNumerical output example: linear regressionStochastic Gradient DescentMatrix Acceleration Goal of Machine Learning 机器学习的目标 假设现在有一组数据 x i , y i {x_i,y_i} xi​,yi​&…

DB-GPT V0.6.3 版本更新:支持 SiliconCloud 模型、新增知识处理工作流等

DB-GPT V0.6.3版本现已上线&#xff0c;快速预览新特性: 新特性 1. 支持 SiliconCloud 模型&#xff0c;让用户体验多模型的管理能力 如何使用&#xff1a; 修改环境变量文件.env&#xff0c;配置SiliconCloud模型 # 使用 SiliconCloud 的代理模型 LLM_MODELsiliconflow_p…

ChromeOS 131 版本更新

ChromeOS 131 版本更新 1. ChromeOS Flex 自动注册 在 ChromeOS 131 中&#xff0c;ChromeOS Flex 的自动注册功能现已允许大规模部署 ChromeOS Flex 设备。与 ChromeOS 零接触注册类似&#xff0c;自动注册将通过组织管理员创建的注册令牌嵌入到 ChromeOS Flex 镜像中。这将…

你好Python

初识Python Python的起源 1989年&#xff0c;为了打发圣诞节假期&#xff0c;Gudio van Rossum吉多 范罗苏姆&#xff08;龟叔&#xff09;决心开发一个新的解释程序&#xff08;Python雏形&#xff09; 1991年&#xff0c;第一个Python解释器诞生 Python这个名字&#xff…

【Linux系统编程】:信号(2)——信号的产生

1.前言 我们会讲解五种信号产生的方式: 通过终端按键产生信号&#xff0c;比如键盘上的CtrlC。kill命令。本质上是调用kill()调用函数接口产生信号硬件异常产生信号软件条件产生信号 前两种在前一篇文章中做了介绍&#xff0c;本文介绍下面三种. 2. 调用函数产生信号 2.1 k…

BlueLM:以2.6万亿token铸就7B参数超大规模语言模型

一、介绍 BlueLM 是由 vivo AI 全球研究院自主研发的大规模预训练语言模型&#xff0c;本次发布包含 7B 基础 (base) 模型和 7B 对话 (chat) 模型&#xff0c;同时我们开源了支持 32K 的长文本基础 (base) 模型和对话 (chat) 模型。 更大量的优质数据 &#xff1a;高质量语料…

apache-tomcat-6.0.44.exe Win10

apache-tomcat-6.0.44.exe Win10

linux-----常用指令

文件和目录操作指令 ls&#xff08;list&#xff09;指令 功能&#xff1a;用于列出目录的内容&#xff0c;包括文件和子目录。示例&#xff1a; ls&#xff1a;列出当前目录下的所有非隐藏文件和目录。例如&#xff0c;在一个包含文件file1.txt、file2.txt和目录dir1的目录中&…

海外外卖APP开发新方向:基于同城外卖系统源码的多元化解决方案

时下&#xff0c;基于同城外卖系统源码的多元化解决方案&#xff0c;正成为海外外卖APP开发的新方向&#xff0c;推动着全球外卖市场的变革。本篇文章&#xff0c;小编将为大家讲述外卖APP开发的新方案。 一、同城外卖系统源码&#xff1a;创新与灵活的基础 同城外卖系统源码…

GhostRace: Exploiting and Mitigating Speculative Race Conditions-记录

文章目录 论文背景Spectre-PHT&#xff08;Transient Execution &#xff09;Concurrency BugsSRC/SCUAF和实验条件 流程Creating an Unbounded UAF WindowCrafting Speculative Race ConditionsExploiting Speculative Race Conditions poc修复flush and reload 论文 https:/…

「Mac畅玩鸿蒙与硬件46」UI互动应用篇23 - 自定义天气预报组件

本篇将带你实现一个自定义天气预报组件。用户可以通过选择不同城市来获取相应的天气信息&#xff0c;页面会显示当前城市的天气图标、温度及天气描述。这一功能适合用于动态展示天气信息的小型应用。 关键词 UI互动应用天气预报数据绑定动态展示状态管理 一、功能说明 自定义…

常用Python自动化测试框架有哪些?

随着技术的进步和自动化技术的出现&#xff0c;市面上出现了一些自动化测试框架。只需要进行一些适用性和效率参数的调整&#xff0c;这些自动化测试框架就能够开箱即用&#xff0c;大大节省了测试时间。而且由于这些框架被广泛使用&#xff0c;他们具有很好的健壮性&#xff0…

彻底认识和理解探索分布式网络编程中的SSL安全通信机制

探索分布式网络编程中的SSL安全通信机制 SSL的前提介绍SSL/TLS协议概述SSL和TLS建立在TCP/IP协议的基础上分析一个日常购物的安全问题 基于SSL的加密通信SSL的安全证书SSL的证书的实现安全认证获取对应的SSL证书方式权威机构获得证书创建自我签名证书 SSL握手通信机制公私钥传输…

嵌入式单片机的运行方式详解

程序的运行方式轮询系统 指的是在程序运行时,首先对所有的硬件进行初始化,然后在主程序中写一个死循环,需要运行的功能按照顺序进行执行,轮询系统是一种简单可靠的方式,一般适用于在只需要按照顺序执行的并且没有外部事件的影响的情况下。 程序的运行过程中出现如按键等需…

python如何保存.npy

数据处理的时候主要通过两个函数&#xff1a; &#xff08;1&#xff09;np.save(“test.npy”&#xff0c;数据结构&#xff09; ----存数据 &#xff08;2&#xff09;data np.load(test.npy") ----取数据 给2个例子如下&#xff1a; 1、存列表 z [[[1, 2, 3], [w]…