您现在的位置: 首页 资讯 > > 正文
JMH – Java基准测试
发布时间:2023-07-03 17:34:02 来源:博客园


(资料图片仅供参考)

官方资源

官方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使用指南

标签:

深圳“双创”综合指数连续6年排名第一 创业密度稳居全国第一

双创由众而积厚成势,因创而破茧成蝶。今年5月,在深圳发布的《大众创业、万众创新研究报告(2021)》显示...

一线工作近22年的缉毒警:我知道坏的是毒品不是人性

  “影子”般的缉毒警:一线工作22年,我知道坏的是毒品不是人性  如果我不继续干,别人也要干,缉...

广东肇庆“毒驾连撞5车致1死”肇事司机被批捕

  1月5日14时30分许,广东肇庆市端州区一男子赵某毒驾连撞5车,致一人死亡。  1月10日,澎湃新闻(ww...

江西最大文物倒卖案宣判:倒卖国家二级文物 9人获刑

  中新网南昌1月10日电 (冷峥嵘 张一怡)江西省共青城市人民法院10日发布消息称,近日,该院依法审结...

青海保障门源地震后生活必需品应急物资

  中新网西宁1月10日电 (记者 孙睿)记者10日从青海省商务厅获悉,青海海北州门源县6 9级地震灾害发...

广西东兴口岸恢复通关 入境需网上预约

  中新社防城港1月10日电 (翟李强)自2022年1月10日零时起,广西东兴口岸和边民互市贸易区恢复人员、...

呼和浩特:寒假期间有条件的学校要开展校内托管服务

  中新网呼和浩特1月10日电 (记者 张林虎)10日,记者从呼和浩特市教育局获悉,在暑假校内托管试点的...

“中国最后一个原始部落”翁丁老寨火灾原因公布

  “中国最后一个原始部落”翁丁老寨火灾原因公布:小孩玩火引起  中新网昆明1月10日电 (罗婕)近日...

北京市十五届人大五次会议胜利闭幕

  北京市十五届人大五次会议胜利闭幕   蔡奇陈吉宁李伟魏小东张延昆出席   张延昆齐静当选市人...

天津市委市政府致全市父老乡亲的慰问信:我们一定能够打赢

  中新网天津1月10日电 (记者 张道正)中共天津市委、天津市人民政府10日发布了“致全市父老乡亲的慰...

天津米面油存量由20天提高至30天 超市菜市场进货量翻倍

  天津米面油存量由20天提高至30天 蔬菜库存量、超市菜市场进货量翻倍  记者10日从天津市商务局获...

兰州名师话“美育”:“尚乐立人”分层培优 以“美”润教

  中新网兰州1月10日电 (记者 刘玉桃 高莹)“实际上音乐课作为一门非高考科目,一直以来没有受到足...

子夜直击,天津寒天战“疫”

  新华全媒+|子夜直击,天津寒天战“疫”  新华社天津1月10日电 题:子夜直击,天津寒天战“疫”...

重庆姐弟被生父扔下坠亡案上诉期结束 一审法院暂未收到两被告人上诉状

  重庆姐弟被生父扔下坠亡案上诉期结束,一审法院暂未收到两被告人上诉状  澎湃新闻记者 谢寅宗 ...

天津:划定封控区 全市开展全员核酸检测

  央视网消息:在各地的最新疫情中,奥密克戎变异株引发天津新增多例本土感染引人关注。截至1月9日下...

江歌母亲江秋莲:尊重法院判决,法律认定在我意料之中

  中新网青岛1月10日电 (记者 胡耀杰)山东省青岛市城阳区人民法院10日对原告江秋莲与被告刘暖曦生命...

中国边疆“北方第一所”:9名民警守护“生命禁区”

  中新网呼伦贝尔1月10日电 题:中国边疆“北方第一所”:9名民警守护“生命禁区”  作者 张玮 ...

辟谣!网传“封控区管控区相继解封”通知并非西安

  中新网1月10日电 据西安发布官方微博消息,1月9日,一则:“鉴于我市目前封控区、管控区相继解封,...

河南安阳9日12时至24时新增11例本土确诊病例

  1月9日12时至24时,河南安阳市新增本土确诊病例11例(汤阴县10例、文峰区1例)。  2020年1月22日至2...

老人5折环卫工8折生活困难免费 这家面馆背后有个暖心事

  老人5折,环卫工人8折,生活困难可以免费吃   这家面馆打折背后,有个暖心故事  见习记者 许...

铁路公安以110幅优秀书画作品庆祝人民警察节

  中新网北京1月10日电 (郭超凯 梁西征)1月10日是中国人民警察节。记者从公安部铁路公安局获悉,近...

本周中东部冷空气频繁 东北等地有降雪

  中国天气网讯 本周我国中东部地区冷空气活动频繁,其中,今天(1月10日)受冷暖空气共同影响,雨雪范...

河南新增本土确诊病例60例

  中新网1月10日电 据河南省卫健委网站消息,1月9日0—24时,全省新增本土确诊病例60例(郑州市24例,...

“打拐”民警眼里的百态人生:见证一份份不愿放弃的爱

  打拐者说   一位“打拐”民警眼里的百态人生  本报记者毛鑫、王瑞平   在公安系统里,“打拐...

迎腊八北京晴天上线 阵风6至7级体感冻人

  中国天气网讯 俗话说“腊七腊八冻掉下巴”,今天(1月10日)迎来腊八节,北京体感冻人,白天阵风六七...

多省份倡议春节“非必要不离开”,这地补贴1000元

伪造国家机关证件典型案例发布 有力打击制假贩假行为

15年照顾170多个新生儿 金牌月嫂“漂”到海外去看娃

江歌母亲江秋莲诉刘鑫案一审将于今日宣判

河南省安阳市两地划为高风险地区 一地划为中风险地区

员工迟到一次罚一千引争议 单位惩戒员工法律边界何在?

以体育人 秀出“青年范儿”

保安、厨师曾被竞业限制 企业滥用竞业限制让员工很苦恼

反诈老陈破圈:人民群众在哪 就把反诈宣传开展到哪

一所中职学校的育人实践

各地严惩恶意欠薪 保障农民工及时拿到工资

中学生成剧本杀行业潜在消费人群 多方助推行业“净化”

“这就是我最好的选择”

对餐饮浪费说“不”(百姓关注)

校园“直通车” 服务“零距离”

琉璃河遗址 两段铭文共证北京三千年建城史

千元修复个人征信报告?银行:“征信修复”都是骗局

琉璃河遗址 两段铭文共证北京三千年建城史

北京公交将开展无人驾驶道路测试

河南郑州调整五地为中风险区域 公路入郑需核酸检测阴性证明

“共享法庭”让金融消费者畅享“智慧司法”便利

《传奇2》网游著作权纠纷案峰回路转 最高法五份裁决四份改判一份发回重审

三代警察:从未放弃的28年

“胡叔叔”的寻亲工作室

天津津南本轮本土疫情第3—20例阳性感染者活动轨迹公布

“团圆”行动刑侦专家吕游 每一个案例都有单独的技术方案

河南“战疫”直面五重考验

开考古书店日均两三个顾客 流量时代她决心仍是只卖书

冬奥开幕在即 “双减”催热冰雪课堂

“不得以任何借口拒收患者”彰显生命至上

天津多站进京车票暂停发售

冷空气来袭广州气温骤降 广东多地发布寒冷预警

“电话发我”——“霸气回应”疫情求助背后的城市温度

天津津南区再增20例阳性感染者,详情公布

电影《农民院士》昆明首映 为观众呈现“把论文写在大地上”

南宁铁路警方春运期间将免费提供被拐儿童父母DNA检测服务

天津津南调整区域风险等级:1个高风险6个中风险!

天津全面加强离津管理 实施离津审批报备制度

口述|“郑州人张嘴做核酸采样的样子,熟练得让人心疼”

青海门源地震“震出”潜逃8年犯罪嫌疑人

天津出现感染奥密克戎本土病例 河南禹州全域为中高风险地区

河南郑州:10日在9个城区开展全员核酸检测

天津市津南区一地调整为高风险地区 多地调整为中风险地区

天津全面加强离津管理:广大市民群众非必要不离津

西安南小张村战“疫”记

河南通过“南水北调饮用水水源保护条例”

河南许昌累计报告143例确诊病例 呼吁16万在外务工者就地过年

重庆颁发中国统一公路养护资质管理后首批证照

“双向奔赴”!河南大学生志愿者为社区抗疫贡献力量

河南濮阳部分景点、剧院1月9日起暂停开放

x 广告
x 广告

Copyright ©  2015-2022 青年自然网版权所有  备案号:皖ICP备2022009963号-20   联系邮箱:39 60 291 42@qq.com