首页 > 编程语言 >java-使用jmh基准测试框架比较五种字符串拼接性能

java-使用jmh基准测试框架比较五种字符串拼接性能

时间:2023-03-25 12:03:46浏览次数:44  
标签:java us jmh 拼接 测试 avgt JmhTest append


java-使用jmh基准测试框架比较五种字符串拼接性能

引言

Java中提供了5种字符串拼接的方法,使用+拼接字符串是最长见的方法。除此还有StringBuilder、StringBuffer、MessageFormat、StringFormat

单纯从拼接执行时间上比较下五种方式的性能。

比较结果

先看下执行结果,其中的Score是执行耗时(微妙),Error可以看做是误差。

执行时间由短到长为:+ < StringBuilder < StringBuilder < MessageFormat < StringFormat

Benchmark                  Mode  Cnt     Score     Error  Units
JmhTest.testMessageFormat  avgt    5   722.346 ± 134.540  us/op
JmhTest.testStringBase     avgt    5     6.905 ±   2.604  us/op
JmhTest.testStringBuffer   avgt    5     8.291 ±   5.311  us/op
JmhTest.testStringBuilder  avgt    5     7.192 ±   3.861  us/op
JmhTest.testStringFormat   avgt    5  1273.906 ±  69.336  us/op

jmh基准测试

添加依赖

<!--基准测试-->
<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>

JMH注解说明

@BenchMarkMode 设置基准测试的模式 【方法或者类】

@OutPutTimeUnit 报告结果的默认时间单位【类、方法】

@Warmup 预热,设置具体的配置参数如次数,时间等

@Measurement 类似预热,但是设置的是测量时的

@Fork 整体测试几次

@State 设置配置对象的作用域,定义线程之间的共享程度

@Setup 线程执行前的配置函数、初始化

@TearDown 测试后处理操作 【方法】

@BenchMark 标记测试基准 【方法】

@OperationsPerInvocation 与基准进行多操作通信,运行JMH调整

  • @BenchMarkMode
    设置运行基准测试的模式,可以选择放在方法上面,只对该方法生效。

    Mode.Throughput : 吞吐量模式,获得单位时间的操作数量,连续运行@BenchMark的方法,计算所有的工作线程的总吞吐量。

    Mode.AverageTime: 平均时间模式, 获得每次操作的平均时间,计算所有工作线程的平均时间。

    Mode.SimpleTime: 时间采样模式, 对每一个操作函数的时间进行采样,连续运行@BenchMark的函数,随机抽取运行所需要的时间。

    Mode.SingleShotTime: 单次触发模式, 测试单次操作的时间,连续运行@BenchMark函数,只运行一次并计算时间: 该模式只是运行一次@BenchMark函数,所以需要预热, 如果基准数值小,使用SimpleTime模式采样。

    Mode.All : 无模式,采用所有的基准模式,效果最好。

编写测试代码

运行main方法启动测试,耐性等待测试完成即可。

import org.openjdk.jmh.annotations.*;
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.text.MessageFormat;
import java.util.concurrent.TimeUnit;

@BenchmarkMode(Mode.AverageTime) //基准测试的默认模式
@OutputTimeUnit(TimeUnit.MICROSECONDS) //时间单位:纳秒、微妙、毫秒、秒、分、时
@State(Scope.Thread)
@Fork(1) //进程数一般设置为1
//@Threads(1) //线程数
@Warmup(iterations = 2,time = 2) //预热迭代次数,time控制每次迭代的间隔时间(默认秒)
@Measurement(iterations = 5,time = 2) //测量迭代次数,time控制每次迭代的间隔时间(默认秒)
public class JmhTest {
    private int _loop = 1000;
    public static void main(String[] args) throws RunnerException {
        Options opt = new OptionsBuilder().include(JmhTest.class.getSimpleName()).build();
        new Runner(opt).run();
    }
    //StringBuffer
    @Benchmark //被测试的方法
    public void testStringBuffer() {
        for(int i = 0; i< _loop; i++){
            StringBuffer sbr = new StringBuffer();
            String s = sbr.append("1111").append(",")
                    .append("2222").append(",")
                    .append("3333").append(",")
                    .append("4444").toString();
        }
    }
    //StringBuilder
    @Benchmark //被测试的方法
    public void testStringBuilder() {
        for(int i = 0; i< _loop; i++){
            StringBuilder sbr = new StringBuilder();
            String s = sbr.append("1111").append(",")
                    .append("2222").append(",")
                    .append("3333").append(",")
                    .append("4444").toString();
        }
    }
    //MessageFormat
    @Benchmark
    public void testMessageFormat() {
        for(int i = 0; i< _loop; i++){
            String s = MessageFormat.format("{0},{1},{2},{3}","1111","2222","3333","4444");
        }
    }
    //String.format
    @Benchmark
    public void testStringFormat() {
        for(int i = 0; i< _loop; i++){
            String s = String.format("%s,%s,%s,%s","1111","2222","3333","4444");
        }
    }
    //字符串拼接
    @Benchmark
    public void testStringBase() {
        for(int i = 0; i< _loop; i++){
            String s = "1111";
            s+=",2222";
            s+=",3333";
            s+=",4444";
        }
    }

}

测试结果说明

以上真对5个函数进行基准测试,测试的配置是每个函数预热执行1次,对之后的5次进行平均执行时间统计。

真对使用Mode.AverageTime模式测试,每个函数执行完成后的输出为:

Result "com.cnpc.epai.researchdata.data.service.JmhTest.testStringFormat":
  1254.609 ±(99.9%) 174.543 us/op [Average]
  (min, avg, max) = (1174.821, 1254.609, 1282.413), stdev = 45.328
  CI (99.9%): [1080.066, 1429.151] (assumes normal distribution)

最终的执行结果是:

Benchmark                  Mode  Cnt     Score     Error  Units
JmhTest.testMessageFormat  avgt    5   722.346 ± 134.540  us/op
JmhTest.testStringBase     avgt    5     6.905 ±   2.604  us/op
JmhTest.testStringBuffer   avgt    5     8.291 ±   5.311  us/op
JmhTest.testStringBuilder  avgt    5     7.192 ±   3.861  us/op
JmhTest.testStringFormat   avgt    5  1273.906 ±  69.336  us/op

其中Score为执行耗时(微妙)Error为误差;

结论:

1.使用StringBuilder的方式是效率最高的。
2.如果不是在循环体中进行字符串拼接的话,直接使用+就好了。
3.如果在并发场景中进行字符串拼接的话,要使用StringBuffer来代替StringBuilder。


标签:java,us,jmh,拼接,测试,avgt,JmhTest,append
From: https://blog.51cto.com/xxjjing/6149139

相关文章

  • 【JAVA】InputStreamReader的正确使用方法
    InputStreamReader是JavaI/O中的一个类,用于将字节流转换为字符流。下面是InputStreamReader的正确使用方法:创建InputStreamReader对象。可以传入一个InputStream对象和一个......
  • 【Java学习笔记】 apache-maven安装
    maven与jdk版本对应关系https://maven.apache.org/download.cgimaven在windows下的安装与环境配置以3.9.1版本为例1.官网下载2.解压(记住路径)3.设置环境变量我......
  • IDEA Rebuild项目错误:Information:java: java.lang.AssertionError: Value of x -1
    模仿lombok工具,我的enumgen工具写完了。  公司的项目emax-rpcapi-list依赖了enumgen后,IDEARebuildProject时,或者mavenpackage/install的时候,出现报错→Information:java......
  • Python字符串_拼接+还是join
    常用的join方法用来将列表或元祖中包含的多个字符串连接成一个字符串newstr = str.join(iterable)  newstr:表示合并后生成的新字符串; str:用于指定合并时的分隔......
  • Java环境变量了解及配置
    1.JDK这个是首先要了解的知识JDK:Java开发工具包,是学习java必须安装的的软件JDK包括Java开发工具和JRE(Java运行环境)JRE又包括基础类库和JVM虚拟机正是有各种操作系统......
  • CentOS 7.8配置Java环境
    一、安装CentOS7.8关闭防火墙systemctlstopfirewalldsystemctldisablefirewalld关闭SELINUXsetenforce0vi/etc/selinux/config将SELINUX=enforcing改为......
  • SAP UI5 本地开发如何实现 XML 和 JavaScript 代码的自动完成和嵌入式 API 文档自动显
    文章目录本文写作动机XML视图元素的文档显示控制器里JavaScript代码的API文档JavaScript控制器代码里方法的自动提示和补全功能UI5ExplorerXML视图里元素名称的自......
  • Jmeter压测报错java.net.BindException: Address already in use: connect
    压力测试并发较高时候,可能会出现Addressalreadyinuse异常java.net.BindException:Addressalreadyinuse:connect atjava.base/java.net.PlainSocketImpl.connect......
  • Java 原子类
    Java内部提供了两种方式来解决线程安全问题,一种是加入synchronized关键字,另一种则是使用Lock锁。虽然说这两种方式都能解决掉线程安全的问题,但是在某些场景下会稍微有......
  • 学习 React 需要具备的 JavaScript 知识
    学习React需要具备的JavaScript知识为什么要学习React?React可以与任何其他库或框架无缝集成,因为React是一个仅视图库(它是ModelViewControlerMVC架构UI......