Java中的时间测量开销

Luk*_*der 45 java timestamp overhead

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

System.currentTimeMillis();
System.nanoTime();
Run Code Online (Sandbox Code Playgroud)

两种方法都已实施native.在深入研究任何C代码之前,有没有人知道是否有任何大量的开销要求调用其中一个?我的意思是,如果我真的不关心额外的精度,那么预期哪个CPU耗时更少?

注意:我使用的是标准的Java 1.6 JDK,但问题可能对任何JRE都有​​效......

bre*_*ttw 43

在此页面上标记为正确的答案实际上是不正确的.由于JVM死代码消除(DCE),堆栈替换(OSR),循环展开等,这不是编写基准测试的有效方法.只有像Oracle的JMH微基准测试框架这样的框架才能正确地测量这样的东西.如果您对此类微基准的有效性有任何疑问,请阅读此文章.

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

@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();
   }
}
Run Code Online (Sandbox Code Playgroud)

以下是结果(在英特尔酷睿i5上):

Benchmark                            Mode  Samples      Mean   Mean err    Units
c.z.h.b.NanoBench.currentTimeMillis  avgt       16   122.976      1.748    ns/op
c.z.h.b.NanoBench.nanoTime           avgt       16   117.948      3.075    ns/op
Run Code Online (Sandbox Code Playgroud)

这表明,System.nanoTime()与~123ns相比,每次调用约118ns时略快一些.然而,同样清楚的是,一旦考虑到平均误差,两者之间几乎没有差别.结果也可能因操作系统而异.但总的说法应该是它们在开销方面基本相同.

更新2015/08/25:虽然这个答案更接近正确,但使用JMH进行测量仍然不正确.测量类似System.nanoTime()自身的东西是一种特殊的扭曲基准测试.答案和权威性文章就在这里.


Whi*_*g34 25

我不相信你需要担心两者的开销.它是如此微小,它本身几乎无法衡量.以下是两者的快速微观基准:

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();
}
Run Code Online (Sandbox Code Playgroud)

最后的结果是:

14297079ns per million
29206842ns per million
Run Code Online (Sandbox Code Playgroud)

它看起来确实System.currentTimeMillis()快了两倍System.nanoTime().然而,无论如何,29ns将比你测量的任何其他东西短得多.System.nanoTime()因为它与时钟无关,所以我会追求精确性和准确性.

  • 不使用变量X,因此可以优化系统调用以获得时间.在稍后的状态下,可以看到循环内没有完成任何工作,并且它们也可以被优化掉.离开很少测量.微基准测试和JIT的危险. (2认同)

Col*_*inD 11

你应该只用它System.nanoTime()来衡量运行一段时间.这不仅仅是纳秒级精度的问题,System.currentTimeMillis()而是"挂钟时间",System.nanoTime()而是用于计时,并且没有其他人所做的"现实世界时间"怪癖.来自Javadoc System.nanoTime():

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关.

  • @Lukas:问题是`System.currentTimeMillis()`可以(我相信)做一些事情,比如插入小时钟调整,这会甩掉时间.可能很少见,但是`nanoTime()`适用于不应受此类事物影响的测量. (3认同)

Nik*_*ohl 6

System.currentTimeMillis() 通常非常快(afaik 5-6 cpu cycle但我不知道我在哪里读过这个),但它的分辨率因不同的平台而异.

因此,如果你需要高精度nanoTime(),如果你担心开销去currentTimeMillis().


min*_*das 6

如果你有时间,请看Cliff Click的演讲,他谈到价格System.currentTimeMillis以及其他事情.