用肉眼看,基准测试似乎只是确定执行某些代码需要花费多长时间的简单问题。 但是通常,这是幼稚的方法。 提供具有准确和可重复结果的有意义的基准并非易事。

在本文中,我们想向您介绍OpenJDK代码工具项目,尤其是JMH。 Java Microbenchmarking线束。 我们已经意识到它已有一段时间了,但是当我们看到它将在Java 9的开发中广泛使用时,它再次引起了我们的注意。

基准测试挑战

那么,为什么t2-t1的普通计时样式不起作用? 除非您正在监视实时系统,否则有许多因素可能会影响基准测试结果并使它们无效。 如果您没有使用像JMH这样的标准化基准测试工具,结果通常会令人怀疑。 并且不要忘记常识。 最重要的因素是常识 。

通常,问题是由特定的系统和VM优化引起的,这些优化可能会使结果在一个经过测试的用例中倾斜,而在另一个测试用例中不起作用。 为了最好或最坏。 诸如意外的GC,预热时间,消除死代码,各种JIT编译器优化,运行时差异,CPU怪癖等问题一直存在。 所有不一定与要进行基准测试的实际因素相关的因素。

哪个…是根据图灵奖获得者Donald Knuth的流行语录创建的:

要更深入地了解JMH如何解决这些问题,请查看Aleksey Shipilev的演讲和博客 。

JMH入门

设置您的项目使用JMH可以通过两种方式完成,作为一个独立项目,或者通过使用maven将依赖项添加为现有项目的一部分。 有关说明可在此处的官方页面上找到 。 顺便说一下,JMH还支持其他JVM语言,例如Scala,Groovy和Kotlin。

设置好环境后,就该移到实际的代码了。 JMH是一个注释驱动的框架,下面通过一个示例让我们看看它的含义。

基准测试示例:比较URL验证

在此测试中,我们将比较两种使用Java验证URL的不同方法:

1.使用java.net.URL构造函数。 如果构造函数由于URL无效而失败,则将引发MalformedURLException。 为了使测试更有趣,还添加了两个变体,将堆栈跟踪深度限制为6种方法,并完全取消了堆栈跟踪。

2.使用正则表达式,至少可以说是一个非常可怕的正则表达式,穆哈哈。 如果该网址不符合该格式,则我们认为该网址无效。

结果将帮助我们对这个问题有一个明确的答案,因此是时候下注了。 如果您在下面的评论部分中弄错了,请告诉我们:)

怪物正则表达式! URL验证模式。 它还活着!!!

非常感谢Hardy Ferentschik ,他让我们与Takipi博客读者分享了他的用例。 Hardy是RedHat的首席工程师,在Hibernate团队工作,还是Hibernate Validator的项目负责人。

基准测试的完整源代码可在GitHub上找到 。 我们建议在最接近的选项卡中将其打开,并将本节的其余部分用作参考手册。

1.基准设置

@BenchmarkMode(Mode.AverageTime)
@Warmup(iterations = 1)
@Measurement(iterations = 2)
@OutputTimeUnit(TimeUnit.NANOSECONDS)

这是发生了什么的解释:

@BenchmarkMode
首先,选择我们要使用的基准测试模式。 JMH为我们提供了4种不同的模式: 吞吐量AverageTimeSampleTime (包括百分位数)和SingleShotTime (一次运行一个方法)。 这些的任何组合也是完全合法的。

@Warmup(迭代次数= 1)
预热迭代次数。

@Measurement(迭代次数= 2)
实际测量迭代次数。 在此示例基准测试中,我们进行了2次迭代,然后取平均分。

@OutputTimeUnit(TimeUnit.NANOSECONDS)
输出结果的时间单位,即对您有意义的java.util.concurrent.TimeUnit的任何值。

2.基准范围–初始状态

设置好之后,我们需要设置基准的初始状态。 在这种情况下,它包括我们将要测试的URL,正则表达式测试的类和URL构造函数测试的类。

每个此类都应使用@State(Scope.Benchmark)进行注释。

另外,对于URL列表,请注意@Param批注,用于将不同的值提供给基准:

@State(Scope.Benchmark)public static class URLHolder {@Param(value = {// should match"http://foo.com/blah_blah","http://142.42.1.1:8080/","http://例子.测试",// should not match"http//foo/","///a",":// should fail"})String url;
}

3.基准代码

现在我们已经设置好配置和初始状态,我们可以前进到实际的基准代码了。

@Benchmark
@Fork(1)
public boolean regExp(ValidateByRegExp validator, URLHolder urlHolder) {return validator.isValid( urlHolder.url );
}

@基准
将此方法标记为基准。

@叉(1)
要运行的试验次数。 每次运行都在不同的JVM中开始。 通过此批注,您还可以提供要包含在测试中的JVM参数。 因此,对于有限的堆栈跟踪测试,我们看到正在使用@Fork(value = 1,jvmArgs =“ -XX:MaxJavaStackTraceDepth = 6”)

4.运行测试

使用选项模式:

public static void main(String[] args) throws Exception {Options opt = new OptionsBuilder().include( ".*" + URLConstraintBenchmark.class.getSimpleName() + ".*" ).build();new Runner( opt ).run();
}

**这绝不是一个完整的指南,只是一个快速的教程,可以帮助您熟悉这些概念。 有关完整的示例集,请在此处查看官方的OpenJDK示例代码。

结果

如果您感到好奇,请以纳秒为单位报告结果。 是时候看看您的赌注是否正确了。 前3个网址合法,后3个网址无效:

我们看到,如果这是一个有效的URL,则验证的正则表达式非常糟糕。 在我们所有的有效网址中,它收到的效果最差。 另一方面,我们看到如果URL无效,则表将旋转,并且正则表达式将获得最佳结果。

在URL构造器方面,我们看不到有效URL的显着差异。 每个变体都提供几乎相同的结果,领先于正则表达式。 对于添加了MalformedURLException的无效URL,还有另一件事需要考虑:异常的堆栈跟踪。 相对于干净的(正则表达式)正则表达式版本,放慢了操作速度。

那么最好的选择是什么? 假设您的大多数数据都包含有效的URL,则URL构造函数的工作方式将是最好的。 尽管在某些情况下使用正则表达式可能会更好,但是如果您假设绝大多数URL都是无效的。

谁使用JMH对其代码进行基准测试?

首先,JMH被构建为OpenJDK项目的内部代码工具。 正如Oracle Java性能专家,JMH项目负责人Aleksey Shipilev告诉我们的那样:

“ JMH摸索着自己的痒:OpenJDK本身的性能工作。 因此,我们有许多特定于功能的基准,用于评估开发中代码的性能。 JMH驱动的基准测试报告了许多性能错误,以展示我们所看到的行为,并提供简单的测试用例来验证JDK更改。”

正如我们所讨论的那样,由于基准测试的准确性主要取决于它如何处理系统行为的各种优化和变化,因此没有比OpenJDK团队更好的团队来构建这种工具。 构建JVM的团队相同,其中包括大多数有用的(至今还很难进行基准测试)优化。

由于开发JMH的团队非常接近基础VM,因此它比其他工具更受青睐,并且可以在许多Java和Scala库和工具中使用。 一些著名的例子包括Twitter的Fingale和供生产使用 的其他 实用程序 , Jersey , Square Okio ,各种Apache项目,Hibernate等。

最后的想法

像许多其他核心Java问题一样,当涉及基准测试时,OpenJDK团队和资源通常是寻找答案的最佳场所。 JMH是一种易于使用的替代方法,可替代自家种植(且大多数情况下是错误的)微基准。 尽管这绝对不会使您摆脱常识来确保基准正确! 我们希望您发现该资源有用,并将继续探索使用JMH创建有意义的基准并与Java社区共享您的发现。 本周,我们还要分享在塔基皮(Takipi)取得的一些新进展。 如果您还没有看到实际的效果,那么这里是您入门所需的一切 。

翻译自: https://www.javacodegeeks.com/2015/11/java-9-code-tools-a-hands-on-session-with-the-java-microbenchmarking-harness.html

Java 9代码工具:使用Java微型基准测试工具的实践会话相关推荐

  1. Java 编译器代码定义的 Java语言的类型 Types

    Java 编译器代码定义的 Java语言的类型 Types /** Copyright (c) 2005, 2013, Oracle and/or its affiliates. All rights ...

  2. java 微型数据库_Java 9代码工具:使用Java微型基准测试工具的实践会话

    java 微型数据库 用肉眼看,基准测试似乎只是确定执行某些代码需要花费多长时间的简单问题. 但是,通常情况下,这是幼稚的方法. 提供具有准确和可重复结果的有意义的基准并非易事. 在本文中,我们将向您 ...

  3. java服务器代码_简单java服务器

    [java]代码库import java.io.InputStream; import java.io.OutputStream; import java.net.*; public class Ch ...

  4. java 注释 代码,如何在Java中注释代码块

    Is it possible to annotate a block of code? E.g. for cycle or simply curly brackets? If so, how? Fir ...

  5. java华容道代码_华容道Java游戏源代码JAVA游戏源码下载

    鉴于JAVA的华容道游戏源码,希望对研讨JAVA游戏的朋友有所帮助.最初运行于西门子是非屏手机上. 华容道Java游戏源代码 (1 folders, 2 files, 1.38 KB, 76.13 K ...

  6. Java实现代码计时功能(Spring计时工具类--StopWatch学习总结)

    使用场景 计算某段程序的执行时间.计算每段线程所耗时间.计算方法调用的执行时间,等等. 传统方式 使用java代码实现计时功能 long startTime = System.currentTimeM ...

  7. java分页代码思路,记录--java 分页 思路 (hibernate关键代码)

    有时会脑袋蒙圈,记录下分页的思路 下面代码是hibernate的分页,其分页就是从第几条数据为起点,取几条数据.比如在mysql中的limit(5,10)取的就是第6条到第10条 在下面代码中的pag ...

  8. java动画代码_利用Java制作字符动画实例代码

    前言 今晚闲来无事,整理了一下电脑中尘封已久的旧代码,看着那些年自己写过的代码,踩过的坑,顿时老泪纵横.正当在感叹之际,突然发现在"马克思"文件夹下出现了一个好玩的项目,那就是N年 ...

  9. js中写java集合代码,JS实现JAVA的List功能

    本次的文章给大家分享了关于JS实现JAVA的List功能的代码,有兴趣的朋友可以看一下function List(){ var list = new Array(); /* 添加元素 */ this. ...

最新文章

  1. 无刷新上传图片,ajax 和 iframe
  2. 江苏省计算机学会科学技术奖,孙国梓
  3. 还记得当年你是如何接触Python的吗?
  4. php中update语句修改多个字段,Myabtis中批量更新update多字段
  5. 取石子游戏(信息学奥赛一本通-T1218)
  6. python aes padding_使用PKCS7Padding在python和Node.js之间进行AES加密
  7. Judy Beta 第10天
  8. spring REST中的内容协商(同一资源,多种展现:xml,json,html)
  9. Linux用户登出之后保持后台进程(nohup)
  10. 造假家族覆灭记:警方联合阿里斩断涉案三千万假耐克产销链
  11. USB3014-应用程序开发(2)
  12. 报表生成器FastReport .Net使用Windows.Forms教程
  13. 基于FPGA的卷积神经网络加速器_余子健
  14. 易趋携手电气风电,推进产品研发项目管理能力进阶
  15. oracle虚拟用户和密码,创建 Virtual Private Catalog(虚拟用户目录)(Oracle 11g)
  16. 2018 Arab Collegiate Programming Contest (ACPC 2018) G. Greatest Chicken Dish (线段树+GCD)
  17. 如何快速学习flex
  18. RJS与ActionView
  19. 【新手入门必看】MaixPy 图像基础知识
  20. 图像特征提取算法:加速鲁棒特征SURF

热门文章

  1. nginx部署laravel需要修改的配置
  2. bladex实现单点登录
  3. 有5家衣服专卖店,每家最多购买3件,用户可以选择离开,可以买衣服,最后打印总共买了几件衣服
  4. hql投影查询之—— [Ljava.lang.Object; cannot be cast to cn.bdqn.guanMingSys.entity.Notice
  5. myeclipse 2016 ci3破解教程(含软件下载)
  6. RBAC(基于角色的权限访问控制)
  7. CV中多的空格导致报错
  8. MySQL中有外键时数据表的删除方法
  9. 外部访问docker容器(docker run -p/-P 指令) docker run -d -p 5000:5000 {hostPort:containerPort(映射所有接口地}
  10. 用python绘制图形_使用Python的turtle画炫酷图形