用Java测量开销

在低水平测量经过时间时,我可以select使用以下任何一种:

System.currentTimeMillis(); System.nanoTime(); 

两种方法都是native实现的。 在挖掘任何C代码之前,有没有人知道是否有任何实质性的开销调用一个或另一个? 我的意思是,如果我真的不关心额外的精度,哪一个会花费更less的CPU时间?

注意:我正在使用标准的Java 1.6 JDK,但这个问题可能适用于任何JRE。

在这个页面上正确的答案实际上是不正确的。 由于JVM无效代码消除(DCE),堆栈replace(OSR),循环展开等,这不是一种有效的编写基准的方法。只有像Oracle的JMH微型基准testing框架这样的框架才能正确地测量这样的结果。 如果您对这些微基准的有效性有任何怀疑,请阅读这篇文章 。

这是System.currentTimeMillis() vs System.nanoTime()的JMH基准:

 @BenchmarkMode(Mode.AverageTime) @OutputTimeUnit(TimeUnit.NANOSECONDS) @State(Scope.Benchmark) public class NanoBench { @Benchmark public long currentTimeMillis() { return System.currentTimeMillis(); } @Benchmark public long nanoTime() { return System.nanoTime(); } } 

以下是结果(在I​​ntel Core i5上):

 Benchmark Mode Samples Mean Mean err Units czhbNanoBench.currentTimeMillis avgt 16 122.976 1.748 ns/op czhbNanoBench.nanoTime avgt 16 117.948 3.075 ns/op 

这表明System.nanoTime()在每调用约118ns时比123ns稍快。 但是,也很清楚,一旦把平均误差考虑在内,两者之间几乎没有什么区别。 结果也可能因操作系统而异。 但是总的来说,应该是它们在开销方面基本上是等价的。

UPDATE 2015/08/25:虽然这个答案更接近于正确的,但是用JMH来衡量还是不正确的。 测量像System.nanoTime()本身是一种特殊的扭曲的基准。 答案和权威文章在这里 。

我不相信你需要担心任何一方的开销。 它是如此之小,它本身几乎不可衡量。 这里有一个快速的微观基准:

 for (int j = 0; j < 5; j++) { long time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { long x = System.currentTimeMillis(); } System.out.println((System.nanoTime() - time) + "ns per million"); time = System.nanoTime(); for (int i = 0; i < 1000000; i++) { long x = System.nanoTime(); } System.out.println((System.nanoTime() - time) + "ns per million"); System.out.println(); } 

最后的结果是:

 14297079ns per million 29206842ns per million 

看来System.currentTimeMillis()System.currentTimeMillis()的两倍。 然而,29ns将比任何你测量的东西都要短得多。 我会去System.nanoTime()精度和准确性,因为它不与时钟相关联。

您应该只使用System.nanoTime()来测量运行需要多长时间。 这不仅仅是纳秒精度的问题, System.currentTimeMillis()是“挂钟时间”,而System.nanoTime()是用于计时的事情,并没有其他的“真实世界时间”怪癖。 从System.nanoTime()的Javadoc:

此方法只能用于测量已用时间,并不涉及系统或挂钟时间的任何其他概念。

如果您有时间,请通过Cliff Click观看这个演讲 ,他谈论System.currentTimeMillis价格以及其他事情。

System.currentTimeMillis()通常真的很快(afaik 5-6 CPU周期,但我不知道我在哪里读了这个),但它的分辨率在不同的平台上有所不同。

所以,如果你需要高精度去nanoTime() ,如果你担心开销currentTimeMillis()

这个问题被接受的答案确实是不正确的。 @brettw提供的备选答案虽然不错,但仍然很清楚细节。

有关此主题的完整处理和这些调用的实际成本,请参阅https://shipilev.net/blog/2014/nanotrusting-nanotime/

要回答问题:

有没有人知道是否有任何实质性的开销调用一个或另一个?

  • 调用System#nanoTime的开销是每次调用15至30纳秒。
  • nanoTime报告的数值,其分辨率,每30纳秒只更改一次

这意味着如果你想要每秒处理数百万个请求,调用nanoTime意味着你正在有效地丢失大量的第二个调用nanoTime 。 对于这样的使用情况,可以考虑来自客户端的测量请求,从而确保您不会陷入协调省略 ,测量队列深度也是一个很好的指标。

如果你不是在一秒钟内尽可能多地完成工作,那么nanoTime并不重要,但是协调的省略仍然是一个因素。

最后,为了完整性, currentTimeMillis不能被使用,不pipe它的成本是多less。 这是因为不能保证在两次通话之间前进。 特别是在有NTP的服务器上, currentTimeMillis会不断移动。 更不用说,计算机测量的大部分东西都不需要一整毫秒。

在理论层面上,对于使用本地线程的VM,并且位于现代抢占式操作系统上,currentTimeMillis可以实现为每个时间片仅读取一次。 据推测,nanoTime实现不会牺牲精度。