当前热门:JMH – Java基准测试
时间:2023-07-04 07:08:38来源:博客园


(资料图)

官方资源

官方Github样例

应用场景对要使用的数据结构不确定,不知道谁的性能更好对历史方法代码重构,要评判改造之后的性能提升多少 (我要做的场景)想准确地知道某个方法需要执行多长时间,以及执行时间和输入之间的相关性对比接口不同实现在给定条件下的吞吐量查看多少百分比的请求在多长时间内完成背景限制(防杠指南)业务场景?因为当前项目是接手比较老的项目,已经有成熟业务在跑,原先的生成模型是nextByCalendarAndRandom, 序号生成是采用两位随机数,然后随机数产生了冲突,一毫秒内产生的两个随机数有冲突,为什么不直接使用 snowflake?原先的生成逻辑 6(商户号) + 15(yyMMddHHmmssSSS 最大长度,可能比15小) + 2(随机数) = 23 (最大长度)如果使用雪花算法,则 6 + 19 = 25 (最大长度),且现在业务方较多,不确定对方是否有限制该字段长度,再就是如果对雪花算法进行裁剪,也不能保证肯定不会出现冲突,经衡量过后,暂时不使用雪花算法,后续业务方能确定长度没有问题,就可以升级这个算法不是分布式的,如果是两台服务器,则出现冲突的可能性就变大了是的,如果两台服务同时运行,然后又同时有请求进来,就有很大的可能性出现冲突,但现在的业务状况是单体架构,只不过做了主备服务,主服务宕机,备份才会启动,暂时不会两台服务同时启动那如果采用 nextByCalendarAndAtomicInteger自增,就表示一毫秒最大只有100个请求能进来?超过就肯定会冲突?是的,这个也是业务决定的,如果我们当前的业务量超过每毫秒超100,那问题可能不是我这里的冲突了,服务会率先被压垮最终的业务采用什么方法?使用了 nextByLocalDateTimeAndAtomicInteger方法,也有每毫秒超100必定重复的限制引用依赖
            org.openjdk.jmh            jmh-core            1.35                            org.openjdk.jmh            jmh-generator-annprocess            1.35        
测试代码
@UtilityClasspublic class IdWork {    @Deprecated    public static String nextByCalendarAndRandom(String merchantNo) {        Calendar now = Calendar.getInstance();        long random1 = Math.round(Math.random() * 9);        long random2 = Math.round(Math.random() * 9);        String timestamp = (now.get(Calendar.YEAR) + "").substring(2)                + (now.get(Calendar.MONTH) + 1)                + now.get(Calendar.DAY_OF_MONTH)                + now.get(Calendar.HOUR_OF_DAY)                + now.get(Calendar.MINUTE)                + now.get(Calendar.SECOND)                + now.get(Calendar.MILLISECOND);        return merchantNo + timestamp + random1 + random2;    }    @Deprecated    public static String nextByLocalDateTimeAndRandom(String merchantNo) {        LocalDateTime now = LocalDateTime.now();        long random1 = Math.round(Math.random() * 9);        long random2 = Math.round(Math.random() * 9);        String timestamp = (now.getYear() + "").substring(2)                + now.getMonthValue()                + now.getDayOfMonth()                + now.getHour()                + now.getMinute()                + now.getSecond()                + (now.getNano() / 1000000);        return merchantNo + timestamp + random1 + random2;    }    @Deprecated    public static String nextByCalendarAndAtomicInteger(String merchantNo) {        Calendar now = Calendar.getInstance();        String timestamp = (now.get(Calendar.YEAR) + "").substring(2)                + (now.get(Calendar.MONTH) + 1)                + now.get(Calendar.DAY_OF_MONTH)                + now.get(Calendar.HOUR_OF_DAY)                + now.get(Calendar.MINUTE)                + now.get(Calendar.SECOND)                + now.get(Calendar.MILLISECOND);        return merchantNo + timestamp + getSeqNo();    }    @Deprecated    public static String nextByLocalDateTimeAndAtomicInteger(String merchantNo) {        LocalDateTime now = LocalDateTime.now();        String timestamp = (now.getYear() + "").substring(2)                + now.getMonthValue()                + now.getDayOfMonth()                + now.getHour()                + now.getMinute()                + now.getSecond()                + (now.getNano() / 1000000);        return merchantNo + timestamp + getSeqNo();    }    public static String nextBySnowflake(String merchantNo) {        return merchantNo + IdGenerator.next();    }    private static AtomicInteger seqNo = new AtomicInteger(1);    private static String getSeqNo() {        int curSeqNo = seqNo.getAndIncrement();        if (curSeqNo > 99) { // 重置,也可以取模            seqNo = new AtomicInteger(1);        }        if (curSeqNo < 10) {            return "0" + curSeqNo;        }        return curSeqNo + "";    }    public static void main(String[] args) {        String next1 = IdWork.nextByCalendarAndRandom("900087");        System.out.println(next1);        String next2 = IdWork.nextByLocalDateTimeAndRandom("900087");        System.out.println(next2);        String next3 = IdWork.nextByCalendarAndAtomicInteger("900087");        System.out.println(next3);        String next4 = IdWork.nextByLocalDateTimeAndAtomicInteger("900087");        System.out.println(next4);        String next5 = IdWork.nextBySnowflake("900087");        System.out.println(next5);    }}
public class IdTest {    @Benchmark    public String getIdBySnowflake() {        return IdWork.nextBySnowflake("900087");    }    @Benchmark    public String nextByCalendarAndRandom() {        return IdWork.nextByCalendarAndRandom("900087");    }    @Benchmark    public String nextByLocalDateTimeAndRandom() {        return IdWork.nextByLocalDateTimeAndRandom("900087");    }    @Benchmark    public String nextByCalendarAndAtomicInteger() {        return IdWork.nextByCalendarAndAtomicInteger("900087");    }    @Benchmark    public String nextByLocalDateTimeAndAtomicInteger() {        return IdWork.nextByLocalDateTimeAndAtomicInteger("900087");    }    public static void main(String[] args) throws RunnerException {        // 吞吐量//        Options opt = new OptionsBuilder()//                .include(IdTest.class.getSimpleName())//                .mode(Mode.Throughput)//                .forks(1)//                .build();        // 平均耗时        Options opt = new OptionsBuilder()                .include(IdTest.class.getSimpleName())                .mode(Mode.AverageTime)                .timeUnit(TimeUnit.NANOSECONDS)                .forks(1)                .build();        new Runner(opt).run();    }// 吞吐量//    Benchmark                                    Mode  Cnt        Score        Error  Units//    IdTest.getIdBySnowflake                     thrpt    5  4070403.840 ±  11302.832  ops/s//    IdTest.nextByCalendarAndAtomicInteger       thrpt    5  4201822.821 ± 177869.095  ops/s//    IdTest.nextByCalendarAndRandom              thrpt    5  4085723.001 ±  47505.309  ops/s//    IdTest.nextByLocalDateTimeAndAtomicInteger  thrpt    5  5036852.390 ± 153313.836  ops/s//    IdTest.nextByLocalDateTimeAndRandom         thrpt    5  5199148.189 ± 405132.888  ops/s// 平均耗时//    Benchmark                                   Mode  Cnt    Score   Error  Units//    IdTest.getIdBySnowflake                     avgt    5  245.739 ± 0.302  ns/op//    IdTest.nextByCalendarAndAtomicInteger       avgt    5  239.174 ± 4.244  ns/op//    IdTest.nextByCalendarAndRandom              avgt    5  251.084 ± 5.798  ns/op//    IdTest.nextByLocalDateTimeAndAtomicInteger  avgt    5  197.332 ± 0.779  ns/op//    IdTest.nextByLocalDateTimeAndRandom         avgt    5  212.105 ± 1.888  ns/op}
概念理解
类型作用域描述备注
BenchmarkElementType.METHOD最重要的注解,标记需要执行的方法
BenchmarkModeElementType.METHOD, ElementType.TYPE统计的维度,有吞吐量,平均耗时,也可以组合使用
ForkElementType.METHOD, ElementType.TYPE复制多个进程来执行方法,每轮默认Iteration循环5次,如果fork 3,则会执行3*5 次,一般默认值1就可以
MeasurementElementType.METHOD, ElementType.TYPE方法控制:循环次数,每次循环时间以及对应的时间单位
WarmupElementType.METHOD,ElementType.TYPE预热,避免系统冷启动导致的性能测试不准
OutputTimeUnitElementType.METHOD, ElementType.TYPE输出时间单位,默认是秒
ParamElementType.FIELD可以指定遍历参数,针对特殊字段测试不同的性能
SetupElementType.METHOD启动类设置,类似 junit Before类型注解
TearDownElementType.METHOD销毁类设置,类似junit After类型注解,一般用于销毁池化的资源
ThreadsElementType.METHOD,ElementType.TYPE
TimeoutElementType.METHOD,ElementType.TYPE
AuxCountersElementType.TYPE辅助计数器,可以统计 @State 修饰的对象中的 public 属性被执行的情况
GroupElementType.METHOD
GroupThreadsElementType.METHOD
CompilerControlElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.TYPE内联扩展是一种特别的用于消除调用函数时所造成的固有时间消耗方法,这里用来控制方法或类是否内联
OperationsPerInvocationElementType.METHOD, ElementType.TYPE

BenchmarkMode 执行模式(可以多个组合执行)

类型描述
Throughput每段时间执行的次数,一般是秒
AverageTime平均时间,每次操作的平均耗时
SampleTime在测试中,随机进行采样执行的时间
SingleShotTime在每次执行中计算耗时
All所有模式
// 常用的注解@BenchmarkMode({Mode.Throughput,Mode.AverageTime})@OutputTimeUnit(TimeUnit.NANOSECONDS)@Warmup(iterations = 3, time = 1, timeUnit = TimeUnit.SECONDS)@Measurement(iterations = 5, time = 1, timeUnit = TimeUnit.SECONDS)@Fork(1)public class BenchmarkTest {    @Benchmark    public long test() {}}// 使用 OptionsBuilder 建造者模式构建 Options, 然后在main方法执行,建议使用Options opt = new OptionsBuilder()        .include(IdTest.class.getSimpleName())        .mode(Mode.AverageTime)        .mode(Mode.Throughput)        .timeUnit(TimeUnit.NANOSECONDS)        .warmupIterations(3)        .warmupTime(TimeValue.seconds(1))        .measurementIterations(5)        .measurementTime(TimeValue.seconds(1))        .forks(1)        .build();
一些提示

避免循环

JVM会对循环进行优化,这样会导致获取的测试结果不准确。

引用资源

jmh-java-microbenchmark-harnessjenkov: java-performancejmh-benchmark-with-examplesJava基准测试工具 —— JMH使用指南

标签:

最新
  • 当前热门:JMH – Java基准测试

    官方资源[官方Github样例](https: github com openjdk jmh tree mas

  • 从缅甸逃回男子自述:水牢满地是血,女子遭囚禁虐打,好看的被卖至娱乐场所_全球关注

    去年年底,李伟(化名)讨要货款时,被客户骗至缅甸后卖给了当地的电诈

  • 当前热文:pe是什么意思的缩写中文_pe是什么意思的缩写

    1、PE=PRICE EARNINGPERSHAREPE是指股票的本益比,也称为“利润收益率

  • 新时代 新征程 新伟业 创建“五星”我先行丨跟着“惠书记”,致富不发愁|最新资讯

    河南日报客户端记者孟向东河南日报社全媒体记者司马连竹通讯员史源远“

  • 中国在世界的地位怎么样?当今世界公认的大国有哪些? 全球时讯

    中国在世界的地位怎么样?钱不是万能的,没有钱是万万不能的。这句话

  • 不是所有电池都属于有害垃圾 专家教你给电池分类-环球微资讯

    家里积攒了不少废干电池,但最近听说电池不属于有害垃圾,那该怎么处理

  • 财产险主要包括哪些? 财产基本险的保险责任是什么?|环球快报

    财产险主要包括哪些?财产险包括财产保险,农业保险,责任保险,保证

  • ai怎么剪切不要的部分 当前热议

    今天来聊聊i怎么剪切不要的部分的文章,现在就为大家来简单介绍下ai怎

  • 环球观速讯丨厦门航空值机网上值机_网上值机是什么意思

    1、网上办理乘机手续——简称“网上值机”服务,是一种方便快捷的登机

  • 全球要闻:香港举行多彩活动庆祝回归祖国26周年

    7月1日,香港多地举行了丰富多彩的活动,庆祝回归祖国26周年。当天下午

  • 第十二届中国西部投资说明会在蓉举行 签约投资合作项目492个_每日短讯

    (单鹏)第十二届中国西部投资说明会暨经济合作项目签约仪式29日下午在成

  • 世界新消息丨李乃文左小青主演的电视剧_左小青主演的电视剧

    1、1996年《黑脸》饰演:岱萍导演:吴天明  1998年《红岩》饰演:孙

  • 上海港湾: 上海港湾关于2023年员工持股计划非交易过户完成的公告

    上海港湾:上海港湾关于2023年员工持股计划非交易过户完成的公告

  • 快讯2023-06-30 09:21:23

    6月30日电,央行今日进行1030亿元7天期逆回购操作,中标利率为1 90%,

  • 世界即时:财通福盛多策略混合型发起式证券投资基金(LOF)基金产品资料概要更新(2023年06月30日公告)

    财通福盛多策略混合型发起式证券投资基金(LOF)基金产品资料概要更新

  • 教师基本功概念_教师基本功有哪些

    1、教师六项技能:普通话、三笔字(毛笔、钢笔、粉笔)、简笔画、说课

  • 旅游
    • 红星歌教案优秀3篇 时快讯

    • 00后贩毒赚5元,获刑6个月!

    • 《青海西秦岭地区金属矿床成矿规律与找矿预测》出版

    • 世界消息!比亚迪另外三款车型确认登陆澳大利亚