处理时间措施的最佳方法?
Best approach for dealing with time measures?
我的目标是编写一个框架来测量方法执行或事务时间并处理测量结果,即存储、分析等。事务可能包括对外部系统的调用,同步或异步等待结果。
已经有一些关于该主题的问题,例如
- "How do I time a method's execution"
- "Measure execution time for a Java method"
- "System.currentTimeMillis vs System.nanoTime"
所有答案归结为三种花时间的方法
System.currentTimeMillis()
System.nanoTime()
Instant.now()
和 Duration
(因为 Java 8)
我知道,所有这些都有一些影响
System.currentTimeMillis()
此方法的结果取决于平台。 Linux 分辨率为 1 毫秒,Windows 分辨率为 10 毫秒(单核)~15 毫秒(多核)。所以测量大型 运行 操作或多次执行短 运行 操作是可以的。
System.nanoTime()
你得到了一个高分辨率的时间测量,具有纳秒精度(但不一定是纳秒精度)并且在 292 年后你会溢出(我可以忍受)。
Instant.now() 和持续时间
从Java8开始就有新的时间API。一个瞬间有一个秒和一个纳秒字段,所以它在对象引用之上使用两个长值(与 Duration
相同)。您还可以获得纳秒精度,具体取决于底层时钟(请参阅“Java 8 Instant.now() with nanosecond resolution?”)。实例化是通过调用 Instant.now()
来完成的,它映射到正常系统时钟的 System.currentTimeMillis()
。
鉴于事实,很明显,只有 System.nanoTime()
才能实现最佳精度,但我的问题更多地针对 最佳实践 来处理一般的措施,不仅包括措施的采取,还包括措施的处理。
Instant 和 Duration 提供最好的 API 支持(计算、比较等),但在标准情况下具有 os 依赖的精度,以及更多的内存开销和创建测量(对象构造,更深的调用堆栈)
System.nanoTime() 和 System.currentTimeMillis() 具有不同级别的精度,但只有基本的 "api" 支持(长数学运算),但速度更快变得更小以保留在内存中。
那么最好的方法是什么?有什么我没有想到的影响吗?还有其他选择吗?
我建议使用 ThreadMXBean
中的 getThreadCpuTime
(另请参阅 )。如果你想衡量一个方法的执行时间,大多数时候你对挂钟的兴趣不大,更多的是CPU执行时间
您过于关注精度的不重要细节。如果你想 measure/profile 执行某些操作,你必须确保这些操作 运行 足够长,以使测量不受一次性工件、线程调度时间的微小差异、垃圾收集的影响或热点优化。在大多数情况下,如果差异变得小于毫秒级,则无法从中得出结论。
更重要的方面是工具是否专为您的任务而设计。 System.currentTimeMillis()
和所有其他基于 API 的挂钟,无论它们是否基于 currentTimeMillis()
,旨在为您提供一个旨在与地球自转及其同步的时钟太阳周围的路径,它加载了 Leap Seconds 和其他校正措施的负担,更不用说您的计算机时钟可能与挂钟不同步并得到校正的事实,例如通过 NTP 更新,在最坏的情况下,当您尝试测量经过的时间时会立即跳转,甚至可能会向后跳转。
相比之下,System.nanoTime()
旨在衡量经过的时间(正是您想要做的),仅此而已。由于其 return 值的来源不明,甚至可能为负,因此只有通过此方法 return 计算的两个值之间的 差异 才有意义。您甚至可以在文档中找到它:
The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
因此,当您想要测量和处理方法执行或事务的运行时间时,System.nanoTime()
是最佳选择。当然,它只提供了一个裸露的 long
值,但不清楚您想要什么样的 API 支持。由于时间点在这里无关紧要甚至会分散注意力,因此您将只有一个持续时间,您可以将其转换为其他 time units or, if you want to use the new time API, you can create a Duration
object using Duration.ofNanos(long)
,允许您添加和减去持续时间值并进行比较,但没有更多你可以做到。您不得将它们与挂钟或基于日历的持续时间混为一谈……
最后一点,文档对限制的描述有点不准确。如果您正在计算 return 由 System.nanoTime()
编辑的两个值之间的差异,数值溢出本身并不坏。由于计数器有一个未指定的来源,您的操作的起始值可能接近 Long.MAX_VALUE
而结束值接近 Long.MIN_VALUE
因为 JVM 的计数器发生了溢出。在这种情况下,计算差异将导致另一次溢出,从而为差异产生正确的值。但是,如果您将差异存储在有符号 long
中,它最多可以保持 2⁶³ 纳秒,将差异限制为最大 292 年,但如果您将其视为 unsigned long,例如通过 Long.compareUnsigned
and Long.toUnsignedString
,您甚至可以处理 2⁶⁴ 纳秒的持续时间,换句话说,您可以通过这种方式测量长达 584 年的流逝时间,如果您的计算机在这期间没有中断的话……
我的目标是编写一个框架来测量方法执行或事务时间并处理测量结果,即存储、分析等。事务可能包括对外部系统的调用,同步或异步等待结果。
已经有一些关于该主题的问题,例如
- "How do I time a method's execution"
- "Measure execution time for a Java method"
- "System.currentTimeMillis vs System.nanoTime"
所有答案归结为三种花时间的方法
System.currentTimeMillis()
System.nanoTime()
Instant.now()
和Duration
(因为 Java 8)
我知道,所有这些都有一些影响
System.currentTimeMillis()
此方法的结果取决于平台。 Linux 分辨率为 1 毫秒,Windows 分辨率为 10 毫秒(单核)~15 毫秒(多核)。所以测量大型 运行 操作或多次执行短 运行 操作是可以的。
System.nanoTime()
你得到了一个高分辨率的时间测量,具有纳秒精度(但不一定是纳秒精度)并且在 292 年后你会溢出(我可以忍受)。
Instant.now() 和持续时间
从Java8开始就有新的时间API。一个瞬间有一个秒和一个纳秒字段,所以它在对象引用之上使用两个长值(与 Duration
相同)。您还可以获得纳秒精度,具体取决于底层时钟(请参阅“Java 8 Instant.now() with nanosecond resolution?”)。实例化是通过调用 Instant.now()
来完成的,它映射到正常系统时钟的 System.currentTimeMillis()
。
鉴于事实,很明显,只有 System.nanoTime()
才能实现最佳精度,但我的问题更多地针对 最佳实践 来处理一般的措施,不仅包括措施的采取,还包括措施的处理。
Instant 和 Duration 提供最好的 API 支持(计算、比较等),但在标准情况下具有 os 依赖的精度,以及更多的内存开销和创建测量(对象构造,更深的调用堆栈)
System.nanoTime() 和 System.currentTimeMillis() 具有不同级别的精度,但只有基本的 "api" 支持(长数学运算),但速度更快变得更小以保留在内存中。
那么最好的方法是什么?有什么我没有想到的影响吗?还有其他选择吗?
我建议使用 ThreadMXBean
中的 getThreadCpuTime
(另请参阅 )。如果你想衡量一个方法的执行时间,大多数时候你对挂钟的兴趣不大,更多的是CPU执行时间
您过于关注精度的不重要细节。如果你想 measure/profile 执行某些操作,你必须确保这些操作 运行 足够长,以使测量不受一次性工件、线程调度时间的微小差异、垃圾收集的影响或热点优化。在大多数情况下,如果差异变得小于毫秒级,则无法从中得出结论。
更重要的方面是工具是否专为您的任务而设计。 System.currentTimeMillis()
和所有其他基于 API 的挂钟,无论它们是否基于 currentTimeMillis()
,旨在为您提供一个旨在与地球自转及其同步的时钟太阳周围的路径,它加载了 Leap Seconds 和其他校正措施的负担,更不用说您的计算机时钟可能与挂钟不同步并得到校正的事实,例如通过 NTP 更新,在最坏的情况下,当您尝试测量经过的时间时会立即跳转,甚至可能会向后跳转。
相比之下,System.nanoTime()
旨在衡量经过的时间(正是您想要做的),仅此而已。由于其 return 值的来源不明,甚至可能为负,因此只有通过此方法 return 计算的两个值之间的 差异 才有意义。您甚至可以在文档中找到它:
The values returned by this method become meaningful only when the difference between two such values, obtained within the same instance of a Java virtual machine, is computed.
因此,当您想要测量和处理方法执行或事务的运行时间时,System.nanoTime()
是最佳选择。当然,它只提供了一个裸露的 long
值,但不清楚您想要什么样的 API 支持。由于时间点在这里无关紧要甚至会分散注意力,因此您将只有一个持续时间,您可以将其转换为其他 time units or, if you want to use the new time API, you can create a Duration
object using Duration.ofNanos(long)
,允许您添加和减去持续时间值并进行比较,但没有更多你可以做到。您不得将它们与挂钟或基于日历的持续时间混为一谈……
最后一点,文档对限制的描述有点不准确。如果您正在计算 return 由 System.nanoTime()
编辑的两个值之间的差异,数值溢出本身并不坏。由于计数器有一个未指定的来源,您的操作的起始值可能接近 Long.MAX_VALUE
而结束值接近 Long.MIN_VALUE
因为 JVM 的计数器发生了溢出。在这种情况下,计算差异将导致另一次溢出,从而为差异产生正确的值。但是,如果您将差异存储在有符号 long
中,它最多可以保持 2⁶³ 纳秒,将差异限制为最大 292 年,但如果您将其视为 unsigned long,例如通过 Long.compareUnsigned
and Long.toUnsignedString
,您甚至可以处理 2⁶⁴ 纳秒的持续时间,换句话说,您可以通过这种方式测量长达 584 年的流逝时间,如果您的计算机在这期间没有中断的话……