代码之家  ›  专栏  ›  技术社区  ›  pdeva

System.nanoTime()是否完全无用?

  •  148
  • pdeva  · 技术社区  · 16 年前

    正如在博客文章中记录的那样 Beware of System.nanoTime() in Java CPU 特定计数器。现在考虑下面的例子,我用它来测量呼叫时间:

    long time1= System.nanoTime();
    foo();
    long time2 = System.nanoTime();
    long timeSpent = time2-time1;
    

    较少的

    考虑到这种情况,是不是System.nanotime现在几乎毫无用处?

    15 回复  |  直到 6 年前
        1
  •  212
  •   Tom Anderson    6 年前

    这个答案是在2011年从当时运行在当时操作系统上的sunjdk实际运行的角度写出来的。那是很久以前的事了! leventov's answer

    那篇文章是错误的,而且 nanoTime 这是安全的。这篇帖子上有一条评论,链接到 a blog post by David Holmes 他是Sun的实时并发人员。它说:

    那么,在Windows上,这个

    FAQ for clock_gettime(CLOCK_REALTIME) ,上面写着:

    1. 时钟获取时间(时钟实时)在所有处理器/内核之间是否一致?(拱门是否重要?例如ppc、arm、x86、amd64、sparc)。

    应该 或者它被认为是马车。

    但是,在x86/x86_64上,可能会看到不同步或变频TSC导致时间不一致。2.4内核确实没有针对这种情况的保护,早期的2.6内核在这里也做得不太好。从2.6.18开始,检测这一点的逻辑更好,我们通常会回到安全的时钟源。

    ppc总是有一个同步的时基,所以这不应该是一个问题。

    纳米时代 电话 clock_gettime(CLOCK_REALTIME) ,那么它在x86上的内核2.6.18中是安全的,并且始终在PowerPC上(因为IBM和摩托罗拉与Intel不同,它们实际上知道如何设计微处理器)。

    遗憾的是,没有提到SPARC或Solaris。当然,我们不知道IBM JVM做什么。但现代Windows和Linux上的Sun JVM做到了这一点。

    four year newer article about Linux's clocks 这可能是有用的。

        2
  •  35
  •   jfs    16 年前

    我做了一些搜索,发现如果一个人是学究,那么是的,它可能被认为是无用的…在特定情况下…这取决于你的需求对时间的敏感程度。。。

    退房 this quote

    实时时钟和 System.nanoTime()都基于 相同的系统调用,因此相同

    使用JavaRTS,所有基于时间的API 线程、截止日期监视等等 第四)基于 通过实时优先级,他们可以 确保将使用适当的代码 在适当的时间执行 实时约束。相反 能够处理的方法 高分辨率时间,无需 时间在之间使用System.nanoTime() 代码中要执行的各个点 运行时间测量应

    Java还有一个 caveat for the nanoTime() 方法:

    此方法只能用于 测量经过的时间,而不是 与系统的任何其他概念相关 或者挂钟时间。返回的值 因此,价值观可能是 否定)。此方法提供 必须是纳秒精度。不 保证如何进行 值经常变化。分歧 在跨度更大的连续调用中 63 纳秒)将不准确 计算由于数值原因而经过的时间 溢流

    似乎可以得出的唯一结论是,nanoTime()不能作为一个准确的值。因此,如果不需要测量相隔仅纳秒的时间,那么即使结果返回值为负值,该方法也足够好。然而,如果您需要更高的精度,他们似乎建议您使用JavaRTS。

        3
  •  27
  •   leventov    6 年前

    从Java 7开始, System.nanoTime() 由JDK规范保证是安全的。 System.nanoTime() 's Javadoc 明确了JVM中所有观察到的调用(即跨所有线程)都是单调的:

    返回的值表示自某个固定但任意的起始时间起的纳秒(可能在将来,因此值可能为负数)。Java虚拟机实例中此方法的所有调用都使用相同的源代码;其他虚拟机实例可能使用不同的源。

    JVM/JDK实现负责消除在调用底层操作系统实用程序(例如,在 Tom Anderson's answer ).

    这个问题的大多数其他旧答案(写于2009-2012年)都表示FUD可能与Java5或Java6相关,但与现代版本的Java不再相关。

    然而,值得一提的是,尽管JDK提供了担保 nanoTime() JDK-8040140 , JDK-8184271 纳米时间() 目前,在OpenJDK的新版本中发现一个新的这样的bug或是一个回归应该不会让任何人感到震惊。

    使用 纳米时间() 对于定时阻塞、间隔等待、超时等,最好将负时差(超时)视为零,而不是抛出异常。 这种做法也是可取的,因为它与中所有类中所有定时等待方法的行为一致 java.util.concurrent.* Semaphore.tryAcquire() , Lock.tryLock() BlockingQueue.poll()

    纳米时间() 仍应优先用于实施定时阻塞、间隔等待、超时等,以 currentTimeMillis() 因为后者受到“时间倒流”现象的影响(例如,由于服务器时间校正),即。E 根本不适合测量时间间隔。 看见 this answer 了解更多信息。

    纳米时间() 例如,对于直接测量代码执行时间,最好使用专门的基准测试框架和分析器 JMH async-profiler 在里面 wall-clock profiling mode .

        4
  •  18
  •   blais    14 年前

    无需争论,只需使用源代码即可。 在这里,针对Linux的SE 6可以得出您自己的结论:

    jlong os::javaTimeMillis() {
      timeval time;
      int status = gettimeofday(&time, NULL);
      assert(status != -1, "linux error");
      return jlong(time.tv_sec) * 1000  +  jlong(time.tv_usec / 1000);
    }
    
    
    jlong os::javaTimeNanos() {
      if (Linux::supports_monotonic_clock()) {
        struct timespec tp;
        int status = Linux::clock_gettime(CLOCK_MONOTONIC, &tp);
        assert(status == 0, "gettime error");
        jlong result = jlong(tp.tv_sec) * (1000 * 1000 * 1000) + jlong(tp.tv_nsec);
        return result;
      } else {
        timeval time;
        int status = gettimeofday(&time, NULL);
        assert(status != -1, "linux error");
        jlong usecs = jlong(time.tv_sec) * (1000 * 1000) + jlong(time.tv_usec);
        return 1000 * usecs;
      }
    }
    
        5
  •  7
  •   Peter Mortensen icecrime    11 年前

    Linux纠正了CPU之间的差异,但Windows没有。我建议您假设System.nanoTime()仅精确到1微秒左右。获得更长时间的一种简单方法是调用foo()1000次或更多次,然后将时间除以1000。

        6
  •  5
  •   Yuvi Masory    15 年前

    我只在多核机器上测试。

        7
  •  5
  •   Basil Vandegriend    14 年前

    我看到了一个负面消息 逝去

        long startNanos = System.nanoTime();
    
        Object returnValue = joinPoint.proceed();
    
        long elapsedNanos = System.nanoTime() - startNanos;
    

    这是在运行AIX的IBM P690(多核)硬件上使用IBM v1.5 JRE 64位实现的。我只见过这种错误发生一次,所以它似乎非常罕见。我不知道原因-是硬件特定的问题,JVM缺陷-我不知道。一般来说,我也不知道nanoTime()的准确性会受到什么影响。

    为了回答最初的问题,我并不认为纳米时间是无用的——它提供了亚毫秒的计时,但它确实存在(不仅仅是理论上的)不准确的风险,你需要考虑到这一点。

        8
  •  2
  •   Aaron Digulla    16 年前

    对于运行Windows XP和JRE 1.5.0_06的Core 2 Duo来说,这似乎不是问题。

    在一个有三个线程的测试中,我看不到System.nanoTime()正在倒退。处理器都很忙,线程偶尔会进入睡眠状态以引起线程的移动。

        9
  •  2
  •   Peter Mortensen icecrime    11 年前

    不,不是。。。这取决于你的CPU,检查一下 High Precision Event Timer 了解如何/为什么根据CPU不同对待事物。

    IBM even suggests

        10
  •  2
  •   Community CDub    8 年前

    Why I get a negative elapsed time using System.nanoTime()?

    1. nanoTime()不是时钟,而是CPU周期计数器。
    2. 返回值除以频率,看起来像时间。
    3. CPU频率可能会波动。
    4. 当您的线程被安排在另一个CPU上时,有可能获得nanoTime(),这会导致负差异。这是合乎逻辑的。CPU上的计数器不同步。
    5. (未确认)我认为如果指令重新排序,即使在同一个CPU上,也可能会得到负面结果。为了防止这种情况发生,您必须调用内存屏障来序列化指令。

    如果System.nanoTime()返回执行的coreID,那就太酷了。

        11
  •  1
  •   knave kilork    14 年前

    Java是跨平台的,nanoTime依赖于平台。如果您使用Java-when,请不要使用nanoTime。我发现使用此函数的不同jvm实现中存在真正的bug。

        12
  •  0
  •   Basu Basu    16 年前

    此方法只能用于 测量经过的时间,而不是 或者挂钟时间。

    Java 5 API Doc

        13
  •  0
  •   Rob Audenaerde    10 年前

    System.currentTimeMillies() 更改系统时钟时发生更改,而 System.nanoTime() 没有,因此后者更安全地测量持续时间。

        14
  •  -3
  •   A5C1D2H2I1M1N2O1R2T1    13 年前

    nanoTime 时间安排极不安全。我在我的基本素性测试算法上进行了试验,它给出的答案对于相同的输入来说几乎是相隔一秒的。别用那种可笑的方法。我需要比“获取时间毫秒”更准确、更精确的东西,但也不像“获取时间毫秒”那么糟糕 .