Ger*_*cke 9 java performance time timing java-8
我的目标是编写一个框架,用于测量方法执行或事务时间以及处理测量,即存储,分析等.事务可能包括调用外部系统,同步或异步等待结果.
关于这个话题已经存在一些问题,比如
所有的答案归结为三种方法来花时间
System.currentTimeMillis()System.nanoTime()Instant.now()和Duration(自Java 8以来)我知道,所有这些都有一些影响
该方法的结果取决于平台.在Linux上你获得1ms的分辨率,在Windows中你得到10ms(单核)~15ms(多核).因此,可以测量大型运行操作或短期运行操作的多次执行.
你得到一个高分辨率的时间测量,具有纳秒精度(但不一定是纳秒精度),并且在292年之后你会得到溢出(我可以忍受它).
从Java 8开始,就有了新的时间API.瞬间有第二个和第二个纳米字段,因此它在对象引用的顶部使用两个长值(相同Duration).您还可以获得纳秒精度,具体取决于基础时钟(请参阅" 具有纳秒分辨率的Java 8 Instant.now()? ").实例化是通过调用Instant.now()哪些映射到System.currentTimeMillis()正常的系统时钟来完成的.
鉴于事实,很明显,最佳精确度只能通过实现System.nanoTime(),但我的问题更多地针对处理一般措施的最佳做法,这不仅包括采取措施,还包括措施处理.
Instant和Duration提供最佳API支持(计算,比较等),但在标准情况下具有os-dependend精度,内存和创建度量的更多开销(对象构造,更深的callstack)
System.nanoTime()和System.currentTimeMillis()具有不同的精度级别,但只有基本的"api"支持(数学操作为long),但更快和更小以保持在内存中.
那么最好的方法是什么?有没有我没想过的含义?还有其他选择吗?
你过分关注精度的不重要细节.如果要测量/分析某些操作的执行,则必须确保这些操作运行的时间足够长,以使测量不受一次性工件,线程调度时间,垃圾收集或HotSpot优化的微小差异的影响.在大多数情况下,如果差异小于毫秒级,则从它们得出结论是没有用的.
更重要的方面是这些工具是否专为您的任务而设计.System.currentTimeMillis()所有其他基于挂钟的API,无论它们是否基于currentTimeMillis(),都旨在为您提供一个时钟,该时钟旨在与地球的旋转及其绕太阳的路径同步,从而加载它与闰秒的负担和其他纠正措施,更不用说你的计算机的时钟可能与挂钟不同并且得到纠正,例如通过NTP更新,在最糟糕的情况下,当你试图测量你的经过时间时跳跃甚至倒退.
相比之下,System.nanoTime()它旨在衡量经过的时间(正是你想要做的),而不是其他任何东西.由于它的返回值有一个未指定的原点,甚至可能是负数,因此只有这个方法返回的两个值之间的差异才有意义.您甚至可以在文档中找到它:
仅当计算在Java虚拟机的同一实例中获得的两个此类值之间的差异时,此方法返回的值才有意义.
因此,当您想要测量和处理方法执行或事务的已用时间时,是可行的方法System.nanoTime().当然,它只提供一个裸long值,但不清楚你想要什么样的API支持.由于时间点是无关紧要的,甚至在这里分散注意力,你只有一个持续时间,你可以转换为其他时间单位,或者,如果你想使用新的时间API,你可以Duration使用创建一个对象Duration.ofNanos(long),允许你添加并减去持续时间值并进行比较,但你可以做的更多.你不能将它们与壁钟或基于日历的持续时间混合在一起......
作为最后一点,文档对限制有点不清楚.如果计算返回的两个值之间的差异System.nanoTime(),则数值溢出本身并不坏.由于计数器具有未指定的原点,因此操作的起始值可能接近,Long.MAX_VALUE而结束值接近,Long.MIN_VALUE因为JVM的计数器有溢出.在这种情况下,计算差异将导致另一次溢出,从而产生差异的正确值.但是如果你将这个差异存储在有符号中long,它可以保持最多2⁶3纳秒,将差异限制为最大292年,但如果你把它视为无符号长,例如通过Long.compareUnsigned和Long.toUnsignedString,你可以处理甚至2⁶⁴纳秒的持续时间,换句话说如果您的计算机没有中断,您可以通过这种方式测量长达584年的时间...
| 归档时间: | 
 | 
| 查看次数: | 1924 次 | 
| 最近记录: |