java基准测试_微基准测试进入Java 9

java基准测试

b05673_mockupcover_normal_ 我已经几个月没有在这里写文章了,这种例外还会继续。 我计划在明年三月左右恢复写作。 本文末尾的说明。 等待! 不完全是最后,因为您可以向下滚动。 它在文章结尾处。 继续阅读!

三年前,我在写有关Java编译器如何优化其执行代码的文章。 或者更确切地说, javac如何做到这一点,而JIT同时做到了。 我制定了一些基准,如Esko Luontola提到的那样,确实有些糟糕。 这些基准旨在表明JIT甚至可以在收集有关代码执行的重要统计数据之前进行优化。

该文章创建于2013年1月。两个月后, JMH (Java Microbenchmark Harness)的第一个源代码上传就发生了。 从那时起,这个工具就发展了很多,并在明年成为Java下一个版本的一部分。 我有一份合同要写一本有关Java 9的书 ,其中的第5章应该涵盖Java 9进行微基准测试的可能性。 这是开始与JMH合作的好理由。

在详细介绍如何使用JMH及其好处之前,让我们先谈谈一些微基准测试。

微基准测试

微基准测试正在衡量某些小代码片段的性能。 它很少使用,在开始为真实的商业环境做微基准测试之前,我们必须三思。 请记住,过早的优化是万恶之源。 一些开发人员对此声明进行了概括,说优化本身是万恶之源,这也许是事实。 特别是如果我们指的是微基准测试。

微基准测试是一种诱使工具,可以在不知道是否值得优化该代码的情况下优化一些小东西。 当我们有一个包含多个模块的庞大应用程序时,它可以在多个服务器上运行,我们如何确保改进应用程序的某些特殊部分可以大大提高性能? 它会偿还增加的收入以产生如此多的利润,以弥补我们在性能测试和开发中花费的成本吗? 我不愿意说你不知道,只是因为这样的说法太笼统了。 从统计学上几乎可以肯定,这种包括微基准测试在内的优化在大多数情况下不会使您感到痛苦。 它会很疼,您可能不会注意到它,甚至可能不会享受它,但这是一个完全不同的故事。

何时使用微基准测试? 我可以看到三个方面:

  1. 您撰写了有关微基准测试的文章。
  2. 您确定了占用应用程序中大部分资源的代码段,并且可以通过微基准测试改进。
  3. 您无法确定将占用应用程序中大部分资源的代码段,但您怀疑它。

第一个笑话。 是否可以:您可以进行微基准测试,以了解其工作原理,然后了解Java代码如何工作,哪些运行得快,哪些不运行。 去年, Takipi发表了一篇文章,他们试图测量Lambda的速度。 阅读这篇非常好的文章,并清楚地表明了博客相对于为印刷品写东西的主要优势。 读者评论并指出了错误,并在本文中进行了更正。

第二是通常的情况。 好的,在读者发表评论之前,纠正了我的观点:第二种应该是通常的情况。 第三是在开发库时,您只是不知道将使用该库的所有应用程序。 在这种情况下,您将尝试优化您认为对大多数可想象的应用程序最关键的部分。 即使在这种情况下,最好还是使用一些示例应用程序。

陷阱

微基准测试的陷阱是什么? 基准测试是作为实验完成的。 我编写的第一个程序是TI计算器代码,我只可以计算该程序为分解两个大(当时为10位)质数的步数。 即使在那个时候,我也使用了古老的俄罗斯秒表来测量懒惰的时间来计算步数。 实验和测量更加容易。

今天,您无法计算CPU执行的步骤数。 程序员无法控制的因素很多,它们可能会改变应用程序的性能,因此无法计算步骤。 我们将测量留给了我们,并且获得了所有测量的所有问题。

测量的最大问题是什么? 我们对某事感兴趣,例如X,我们通常无法衡量。 因此,我们改为测量Y,并希望Y和X的值耦合在一起。 我们要测量房间的长度,但是要测量激光束从一端到达另一端所花费的时间。 在这种情况下,长度X和时间Y紧密耦合。 很多时候,X和Y仅或多或少地相关。 在大多数情况下,人们进行测量时,X和Y根本不相关。 人们仍然把钱和更多的钱花在这种测量支持的决策上。 以政治选举为例。

微基准测试没有什么不同。 很难做到这一点。 如果您对细节和可能的陷阱感兴趣, Aleksey Shipilev会提供一个不错的一小时视频。 第一个问题是如何衡量执行时间。 小代码运行时间很短,并且在测量开始和结束时System.currentTimeMillis()可能只是返回相同的值,因为我们仍处于同一毫秒内。 即使执行时间为10ms,纯粹由于我们测量时间的量化,测量误差仍然至少为10%。 幸运的是有System.nanoTime() 。 我们开心吗,文森特?

并不是的。 如文档所述 nanoTime() 返回正在运行的Java虚拟机的高分辨率时间源的当前值,以纳秒为单位。 什么是“当前”? 何时进行调用? 还是退回时? 还是介于两者之间? 选择您想要的一个,您仍然可能失败。 所有Java实现都应保证在最近1000ns内该当前值相同。

文档中使用nanoTime()之前的另一个警告: 跨越大约292年(263纳秒)的连续调用中的差异由于数值溢出而无法正确计算经过时间。

292年? 真?

还有其他问题。 启动Java代码时,代码的前几千次执行将在没有运行时优化的情况下进行解释或执行。 与静态编译语言(如Swift,C,C ++或Golang)的编译器相比,JIT的优势在于,它可以从代码的执行中收集运行时信息,并且当发现上次执行的编译基于最近的版本时,它可能会更好运行时统计信息将再次编译代码。 对于也尝试使用统计信息调整其操作参数的垃圾收集可能同样如此。 因此,编写良好的服务器应用程序会随着时间的推移获得一些性能。 它们的启动速度稍慢,然后变得更快。 如果重新启动服务器,则整个迭代将再次开始。

如果执行微型基准测试,则应注意这种行为。 您是否要在预热期间测量应用程序的性能,或者在操作过程中如何真正执行应用程序?

解决方案是尝试考虑所有这些警告的微型基准测试工具。 Java 9是JMH。

什么是JMH?

“ JMH是用于构建,运行和分析以Java和其他针对JVM的其他语言编写的nano / micro / milli / macro基准测试的Java工具。” (摘自JMH的官方网站 )

您可以将jmh作为独立于您测量的实际项目的单独项目运行,也可以仅将测量代码存储在单独的目录中。 该线束将根据生产类文件进行编译并执行基准测试。 如我所见,最简单的方法是使用Gradle插件执行JMH。 您将基准测试代码存储在名为jmh的目录中(与maintest处于同一级别),并创建可以启动基准测试的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.io.IOException;public class MicroBenchmark {public static void main(String... args) throws IOException, RunnerException {Options opt = new OptionsBuilder().include(MicroBenchmark.class.getSimpleName()).forks(1).build();new Runner(opt).run();}

有一个不错的构建器界面用于配置,还有一个可以执行基准测试的Runner类。

玩一点

在《 Java 9编程实例》一书中,其中一个例子是Mastermind游戏 。 第五章是关于并行解决游戏以加快猜测速度的所有内容。 (如果您不了解该游戏,请在Wikipedia上阅读它,我不想在这里解释它,但是您需要它来理解以下内容。)

正常的猜测很简单。 有一个隐藏的秘密。 秘诀是从6种颜色中选择4种不同颜色的4个钉子。 当我们猜测时,我们一个接一个地考虑可能的颜色变化,并向表格提出问题:如果这种选择是秘密,所有答案都是正确的吗? 换句话说:这个猜测可以隐藏吗,或者以前的答案在答案中有矛盾吗? 如果可以将这种猜测作为秘密,那么我们将尝试将钉子放在桌子上。 答案可能是4/0(alleluia)或其他。 在后一种情况下,我们继续搜索。 这样,可以通过五个步骤解决6色4列表格。

为了简化和可视化,我们用数字命名颜色,例如01234456789 (在jmh基准中有10种颜色,因为6种颜色还不够)和6种钉子。 这个秘密,我们使用是987654 ,因为这是最后的猜测,我们从去123456123457等。

当我于1983年8月在瑞典学校计算机(ABC80)上用BASIC语言首次编写此游戏时,在运行于40MHz 6种颜色,4个位置的z80处理器上,每次猜测都花了20到30秒。 今天,我的MacBook Pro可以使用10种颜色和6种钉子在大约每秒7次的单线程中玩整个游戏。 但是,当我的机器中有4个处理器支持8个并行线程时,这还不够。

为了加快执行速度,我将猜测空间划分为相等的间隔,并启动了单独的猜测器,每个猜测器将猜测分散到阻塞队列中。 主线程从队列中读取并在猜测出现时将其放在表上。 万一某些线程创建一个猜测而主线程尝试将其用作猜测时已过时,则可能需要一些后期处理,但我们仍希望可以大大提高速度。

真的加快了猜测速度吗? 那是JMH的目的。

为了运行基准测试,我们需要一些可以实际执行游戏的代码

@State(Scope.Benchmark)public static class ThreadsAndQueueSizes {@Param(value = {"1", "4", "8", "16", "32"})String nrThreads;@Param(value = { "1", "10", "100", "1000000"})String queueSize;}@Benchmark@Fork(1)public void playParallel(ThreadsAndQueueSizes t3qs) throws InterruptedException {int nrThreads = Integer.valueOf(t3qs.nrThreads);int queueSize = Integer.valueOf(t3qs.queueSize);new ParallelGamePlayer(nrThreads, queueSize).play();}@Benchmark@Fork(1)public void playSimple(){new SimpleGamePlayer().play();}

JMH框架将多次执行代码,以测量使用多个参数运行的时间。 将执行方法playParallel来运行playParallel和32个线程的算法,每个线程的最大队列长度分别为playParallel和一百万。 当队列已满时,各个猜测者将停止猜测,直到主线程从队列中拉出至少一个猜测为止。

我怀疑如果我们有很多线程,并且我们不限制队列的长度,那么工作线程将使用仅基于空表的初始猜测来填充队列,因此不会带来太多价值。 执行将近15分钟后,我们会看到什么?

Benchmark                    (nrThreads)  (queueSize)   Mode  Cnt   Score   Error  Units
MicroBenchmark.playParallel            1            1  thrpt   20   6.871 ± 0.720  ops/s
MicroBenchmark.playParallel            1           10  thrpt   20   7.481 ± 0.463  ops/s
MicroBenchmark.playParallel            1          100  thrpt   20   7.491 ± 0.577  ops/s
MicroBenchmark.playParallel            1      1000000  thrpt   20   7.667 ± 0.110  ops/s
MicroBenchmark.playParallel            4            1  thrpt   20  13.786 ± 0.260  ops/s
MicroBenchmark.playParallel            4           10  thrpt   20  13.407 ± 0.517  ops/s
MicroBenchmark.playParallel            4          100  thrpt   20  13.251 ± 0.296  ops/s
MicroBenchmark.playParallel            4      1000000  thrpt   20  11.829 ± 0.232  ops/s
MicroBenchmark.playParallel            8            1  thrpt   20  14.030 ± 0.252  ops/s
MicroBenchmark.playParallel            8           10  thrpt   20  13.565 ± 0.345  ops/s
MicroBenchmark.playParallel            8          100  thrpt   20  12.944 ± 0.265  ops/s
MicroBenchmark.playParallel            8      1000000  thrpt   20  10.870 ± 0.388  ops/s
MicroBenchmark.playParallel           16            1  thrpt   20  16.698 ± 0.364  ops/s
MicroBenchmark.playParallel           16           10  thrpt   20  16.726 ± 0.288  ops/s
MicroBenchmark.playParallel           16          100  thrpt   20  16.662 ± 0.202  ops/s
MicroBenchmark.playParallel           16      1000000  thrpt   20  10.139 ± 0.783  ops/s
MicroBenchmark.playParallel           32            1  thrpt   20  16.109 ± 0.472  ops/s
MicroBenchmark.playParallel           32           10  thrpt   20  16.598 ± 0.415  ops/s
MicroBenchmark.playParallel           32          100  thrpt   20  15.883 ± 0.454  ops/s
MicroBenchmark.playParallel           32      1000000  thrpt   20   6.103 ± 0.867  ops/s
MicroBenchmark.playSimple            N/A          N/A  thrpt   20   6.354 ± 0.200  ops/s

(分数越高,越好。)它表明,如果启动16个线程并且在某种程度上限制了队列的长度,我们将获得最佳性能。 在一个线程(一个主线程和一个工作线程)上运行并行算法要比单线程实现慢一些。 这似乎没问题:我们有启动新线程以及线程之间通信的开销。 我们拥有的最大性能约为16个线程。 由于我们可以在这台机器上拥有8个内核,因此我们希望能看到8个内核。为什么?

如果我们用随机的东西替换标准密码987654 (即使对于CPU来说,它也会在一段时间后很无聊)会发生什么?

Benchmark                    (nrThreads)  (queueSize)   Mode  Cnt   Score   Error  Units
MicroBenchmark.playParallel            1            1  thrpt   20  12.141 ± 1.385  ops/s
MicroBenchmark.playParallel            1           10  thrpt   20  12.522 ± 1.496  ops/s
MicroBenchmark.playParallel            1          100  thrpt   20  12.516 ± 1.712  ops/s
MicroBenchmark.playParallel            1      1000000  thrpt   20  11.930 ± 1.188  ops/s
MicroBenchmark.playParallel            4            1  thrpt   20  19.412 ± 0.877  ops/s
MicroBenchmark.playParallel            4           10  thrpt   20  17.989 ± 1.248  ops/s
MicroBenchmark.playParallel            4          100  thrpt   20  16.826 ± 1.703  ops/s
MicroBenchmark.playParallel            4      1000000  thrpt   20  15.814 ± 0.697  ops/s
MicroBenchmark.playParallel            8            1  thrpt   20  19.733 ± 0.687  ops/s
MicroBenchmark.playParallel            8           10  thrpt   20  19.356 ± 1.004  ops/s
MicroBenchmark.playParallel            8          100  thrpt   20  19.571 ± 0.542  ops/s
MicroBenchmark.playParallel            8      1000000  thrpt   20  12.640 ± 0.694  ops/s
MicroBenchmark.playParallel           16            1  thrpt   20  16.527 ± 0.372  ops/s
MicroBenchmark.playParallel           16           10  thrpt   20  19.021 ± 0.475  ops/s
MicroBenchmark.playParallel           16          100  thrpt   20  18.465 ± 0.504  ops/s
MicroBenchmark.playParallel           16      1000000  thrpt   20  10.220 ± 1.043  ops/s
MicroBenchmark.playParallel           32            1  thrpt   20  17.816 ± 0.468  ops/s
MicroBenchmark.playParallel           32           10  thrpt   20  17.555 ± 0.465  ops/s
MicroBenchmark.playParallel           32          100  thrpt   20  17.236 ± 0.605  ops/s
MicroBenchmark.playParallel           32      1000000  thrpt   20   6.861 ± 1.017  ops/s

由于我们不需要仔细研究所有可能的变化,因此性能得以提高。 如果是一个线程,则增加一倍。 在有多个线程的情况下,增益不是很多。 请注意,这并不能提高代码本身的速度,只能使用统计的随机机密来更实际地进行测量。 我们还可以看到,在8个线程中获得16个线程不再有意义。 仅当我们选择接近变体结尾的秘密时,这才有意义。 为什么? 从您在这里看到的内容以及从GitHub中提供的源代码中,您可以给出答案。

摘要

《 Java 9示例编程》计划于2017年2月发行。但是,由于我们生活在一个开放源代码的世界中,因此您可以控制发布者对1.xx-SNAPSHOT版本的访问。 现在,我告诉了您在编写本书代码时使用的初步GitHub URL,您还可以预购eBook,并提供反馈以帮助我创建更好的书。

翻译自: https://www.javacodegeeks.com/2016/09/microbenchmarking-comes-java-9.html

java基准测试

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

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

相关文章

python周天为一周的开始_从两个月减肥四十斤说起,不懈坚持,才是一个人最核心的竞争力。...

大学毕业了十年,我的身材失控了十年。我对我的胖身材已经习以为常了十年了,我从来没想过改变,因为我也没有毅力改变。有一句话说的,人越胖,就越懒。因为我胖,所以我不跑步,我也不爱外出。只要你…

java实现线程的方式_java多线程实现的四种方式

java多线程实现的四种方式1、继承Thread类,重写run方法(其实Thread类本身也实现了Runnable接口)2、实现Runnable接口,重写run方法3、实现Callable接口,重写call方法(有返回值)4、使用线程池(有返回值)1、继承Thread类,重写run方法…

本地运行flowable_在CockroachDB上运行Flowable

本地运行flowable什么是CockroachDB? CockroachDB是一个我一直关注了很长时间的项目。 这是一个开放源代码的Apache 2许可数据库( Github链接 ),该数据库在很大程度上汲取了Google Spanner白皮书的启发 。 它的核心是可水平扩展的…

win10禁用驱动程序强制签名_图文细说 win10系统未检测到第三个监视器的途径 -win10使用教程...

据统计调查,好多朋友都在为图文细说 win10系统未检测到第三个监视器的途径 的问题而烦恼,小编决定将解决的办法分享给大家。对于电脑菜鸟而言看到图文细说 win10系统未检测到第三个监视器的途径 是很无奈的,试着独自一个人解决图文细说 win10…

安装openstack_午餐前如何安装OpenStack Cloud

安装openstack图1. QuickStart的内部工作原理 云安装程序 如果我告诉您可以在必须停下来吃午餐之前进行OpenStack Cloud环境设置,该怎么办? 您会感到惊讶吗? 你今天可以做吗? 在大多数情况下,我敢打赌您的答案是不…

5e怎么绑定一键跳投_怎么开通淘宝亲情账号 淘宝亲情账号申请步骤【详解】

据官方消息,淘宝将在2月1日上线“亲情账号”功能。那么 淘宝亲情账号怎么开通?在哪申请? 下面为大家介绍下,一起来看看。亲情账号用户在淘宝账号中可以创建“父亲”或“母亲”角色关系,对父母发出注册邀请或直接绑定他们的账号。完成亲情关…

windows功能_你的Windows杀毒软件有这个功能吗?

安全软件首推-火绒,良心之作。比起360安全卫士、腾讯电脑管家,它无广告,无捆绑,无劫持,无弹窗,还免费。我认为最喜人最贴心的功能属它的‘弹窗拦截’了,可以拦截程序推送烦人的弹窗。五大浓缩亮…

base64 二进制流java_读取和base64编码二进制文件

我m trying to read a binary file from the filesystem and then base64 encode it in JavaScript. I使用FileReader API读取数据并找到base64编码器here .我的代码似乎接近工作,问题是生成的base64数据是错误的 . 这是我到目前为止所得到的:function s…

drools dmn_使用Drools的DMN运行时示例

drools dmn正如去年宣布的那样 ,Drools 7.0将在合规级别3对DMN模型提供全面的运行时支持。 在撰写本文时,运行时实现已完成,并且该团队现在正在努力进行改进,以进行错误修复和用户友好。 不幸的是,对于7.0版本&#…

笔记本电脑关机后指示灯还亮_汽车仪表常见指示符号之清洗液指示灯,灯亮了怎么办?...

清洗液指示灯就是玻璃水指示灯,用来显示玻璃水的储存量的,平时为熄灭状态,当玻璃水不足时就会点亮提醒驾驶员该添加了。添加后清洗液指示灯还亮的说明出现故障,检查玻璃水电机,相关线路保险丝等,行车中此灯…

xxx钻石商城功能开发需求

文章目录1. 买家小程序端1.1. 首页1.2. 店铺1.2.1. 搜索门店1.2.2. 门店信息1.2.3. 预约试戴1.3. 购物袋1.3.1. 加入购物车1.3.2. 编辑购物车1.4. 个人中心1.4.1. 个人信息1.4.2. 实名认证1.4.3. 我的等级1.4.4. 查看收益1.4.4.1 门店收益1.4.4.1.1查看结算单1.4.4.2 分享收益1…

drools6.5_Drools 6.5.0.Final可用

drools6.5最新和最出色的Drools 6.5.0.Final版本现已可供下载。 这是我们以前的版本的增量版本,重点是一些重要的改进以完善6.x系列。 您可以在此处找到更多详细信息,下载和文档: Drools网站 资料下载 文献资料 发行说明 请阅读下面的一…

c++ vector 一部分_C++ vector 使用注意事项

1、初始化c 11以后新增了大括号{}的初始化方式&#xff0c;需要注意与()的区别,如&#xff1a;std::vector<int> vecTest1(5); //初始化5个元素&#xff0c;每个都是0std::vector<int> vecTest2{ 5 }; //初始化1个元素&#xff0c;值是52、添加元素&#xff1a;pus…

react打包后图片丢失_React中型项目的优化实践

本文可能涉及的内容--项目介绍整个项目大概有60个页面&#xff0c;用到的组件大概150&#xff0c;package里面的依赖大概有70个&#xff0c;应该勉强算得上是一个中型的React的项目了。下面给大家看看我们现在build一次项目的结果--打包时间约150s&#xff0c;打包完之后的资源…

cuba.platform_CUBA Platform 6.3的新增功能

cuba.platform我们很自豪地宣布新版本的CUBA平台和Studio全面上市&#xff01; 也许这是有史以来功能最丰富的平台版本之一–在各个级别上都有重要的变化&#xff1a;体系结构&#xff0c;可扩展性&#xff0c;API可用性和性能。 本文介绍了该平台的主要增强功能。 发行说明中…

如何通过命令终端访问本地/局域网/远程的MySQL数据库_访问数据库_连接数据库_登录数据库

文章目录Windows系统下访问本地MySQL数据库访问远程主机的MySQL数据库本地安装了MySQL数据库本地没有安装MySQLLinux系统下退出数据库登录Windows系统下 访问本地MySQL数据库 使用命令终端访问本地MySQL数据库&#xff0c;打开终端直接输入以下命令语句&#xff1a; mysql …

科大讯飞 jason word_2019科大讯飞全球1024开发者节开幕啦

2019年10月24日&#xff0c;属于开发者的共同节日2019科大讯飞全球1024开发者节于合肥滨湖国际会展中心盛大启幕。以“A.I.前进&#xff0c;拼世界”为主题的本届大会&#xff0c;将集结120位行业大咖主题演讲、20场行业分论坛详解全域A.I.&#xff0c;科大讯飞的1024计划3.0、…

多线程线程池的实现java_如何在Java中实现线程池

多线程线程池的实现java线程是独立程序的执行路径。 在java中&#xff0c;每个线程都扩展java.lang.Thread类或实现java.lang.Runnable。 多线程是指在一个任务中同时执行两个或多个线程。在多线程中&#xff0c;每个任务可以有多个线程&#xff0c;并且这些线程可以异步或同步…

Windows 使用命令执行 sql 脚本文件

文章目录MySQL 数据库方法一&#xff1a;使用 mysql 命令方法二&#xff1a;使用 source 命令Oracle 数据库MySQL 数据库 方法一&#xff1a;使用 mysql 命令 未配置 MySQL 的环境变量&#xff0c;则需要进入 MySQL 的 bin 目录下才能执行 mysql 命令已配置 MySQL 的环境变量…