Java System.nanoTime() 完全没用吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/510462/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 15:33:49  来源:igfitidea点击:

Is System.nanoTime() completely useless?

javananotime

提问by pdeva

As documented in the blog post Beware of System.nanoTime() in Java, on x86 systems, Java's System.nanoTime() returns the time value using a CPUspecific counter. Now consider the following case I use to measure time of a call:

正如博客文章Beware of System.nanoTime() in Java 中所述,在 x86 系统上,Java 的 System.nanoTime() 使用CPU特定计数器返回时间值。现在考虑我用来测量通话时间的以下案例:

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

Now in a multi-core system, it could be that after measuring time1, the thread is scheduled to a different processor whose counter is less than that of the previous CPU. Thus we could get a value in time2 which is lessthan time1. Thus we would get a negative value in timeSpent.

现在在多核系统中,可能是在测量 time1 后,线程被调度到计数器小于前一个 CPU 的不同处理器。因此,我们可以在 time2 中获得一个小于time1 的值。因此,我们将在 timeSpent 中得到一个负值。

Considering this case, isn't it that System.nanotime is pretty much useless for now?

考虑到这种情况,System.nanotime 是不是现在几乎没什么用了?

I know that changing the system time doesn't affect nanotime. That is not the problem I describe above. The problem is that each CPU will keep a different counter since it was turned on. This counter can be lower on the second CPU compared to the first CPU. Since the thread can be scheduled by the OS to the second CPU after getting time1, the value of timeSpent may be incorrect and even negative.

我知道更改系统时间不会影响纳米时间。这不是我上面描述的问题。问题是每个 CPU 都会保持一个不同的计数器,因为它被打开了。与第一个 CPU 相比,第二个 CPU 上的此计数器可能更低。由于线程在得到time1后可以被OS调度到第二个CPU上,timeSpent的值可能不正确,甚至是负数。

采纳答案by Tom Anderson

This answer was written in 2011 from the point of view of what the Sun JDK of the time running on operating systems of the time actually did. That was a long time ago! leventov's answeroffers a more up-to-date perspective.

这个答案是从当时运行在当时操作系统上的 Sun JDK 实际做了什么的角度写于 2011 年的。那是很久以前的事!列文托夫的回答提供了更新的观点。

That post is wrong, and nanoTimeis safe. There's a comment on the post which links to a blog post by David Holmes, a realtime and concurrency guy at Sun. It says:

那个帖子是错误的,nanoTime是安全的。这篇文章的评论链接到了 David Holmes 的一篇博客文章,他是 Sun 的一名实时和并发专家。它说:

System.nanoTime() is implemented using the QueryPerformanceCounter/QueryPerformanceFrequency API [...] The default mechanism used by QPC is determined by the Hardware Abstraction layer(HAL) [...] This default changes not only across hardware but also across OS versions. For example Windows XP Service Pack 2 changed things to use the power management timer (PMTimer) rather than the processor timestamp-counter (TSC) due to problems with the TSC not being synchronized on different processors in SMP systems, and due the fact its frequency can vary (and hence its relationship to elapsed time) based on power-management settings.

System.nanoTime() 是使用 QueryPerformanceCounter/QueryPerformanceFrequency API 实现的 [...] QPC 使用的默认机制由硬件抽象层 (HAL) 决定 [...] 此默认值不仅跨硬件而且跨操作系统发生变化版本。例如,Windows XP Service Pack 2 更改了使用电源管理计时器 (PMTimer) 而不是处理器时间戳计数器 (TSC) 的内容,因为 TSC 在 SMP 系统中的不同处理器上不同步的问题,以及它的频率可以根据电源管理设置而变化(以及其与经过时间的关系)。

So, on Windows, this wasa problem up until WinXP SP2, but it isn't now.

因此,在 Windows 上,这WinXP SP2 之前一个问题,但现在不是。

I can't find a part II (or more) that talks about other platforms, but that article does include a remark that Linux has encountered and solved the same problem in the same way, with a link to the FAQ for clock_gettime(CLOCK_REALTIME), which says:

我找不到关于其他平台的第二部分(或更多),但该文章确实包含了 Linux 遇到并以相同方式解决相同问题的评论,以及指向clock_gettime(CLOCK_REALTIME) 常见问题解答的链接,其中说:

  1. Is clock_gettime(CLOCK_REALTIME) consistent across all processors/cores? (Does arch matter? e.g. ppc, arm, x86, amd64, sparc).

It shouldor it's considered buggy.

However, on x86/x86_64, it is possible to see unsynced or variable freq TSCs cause time inconsistencies. 2.4 kernels really had no protection against this, and early 2.6 kernels didn't do too well here either. As of 2.6.18 and up the logic for detecting this is better and we'll usually fall back to a safe clocksource.

ppc always has a synced timebase, so that shouldn't be an issue.

  1. 所有处理器/内核的clock_gettime(CLOCK_REALTIME) 是否一致?(arch 重要吗?例如 ppc、arm、x86、amd64、sparc)。

应该或被认为有问题。

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

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

So, if Holmes's link can be read as implying that nanoTimecalls clock_gettime(CLOCK_REALTIME), then it's safe-ish as of kernel 2.6.18 on x86, and always on PowerPC (because IBM and Motorola, unlike Intel, actually know how to design microprocessors).

因此,如果 Holmes 的链接可以被解读为暗示nanoTime调用clock_gettime(CLOCK_REALTIME),那么它在 x86 上的内核 2.6.18 中是安全的,并且始终在 PowerPC 上(因为 IBM 和摩托罗拉,与英特尔不同,实际上知道如何设计微处理器)。

There's no mention of SPARC or Solaris, sadly. And of course, we have no idea what IBM JVMs do. But Sun JVMs on modern Windows and Linux get this right.

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

EDIT: This answer is based on the sources it cites. But i still worry that it might actually be completely wrong. Some more up-to-date information would be really valuable. I just came across to a link to a four year newer article about Linux's clockswhich could be useful.

编辑:这个答案是基于它引用的来源。但我仍然担心它实际上可能是完全错误的。一些更新的信息将非常有价值。我刚刚找到了一篇关于 Linux 时钟四年新文章的链接,这可能很有用。

回答by Ric Tokyo

No, it's not... It just depends on your CPU, check High Precision Event Timerfor how/why things are differently treated according to CPU.

不,它不是......它只取决于你的 CPU,检查高精度事件计时器,了解如何/为什么根据 CPU 对事物进行不同的处理。

Basically, read the source of your Java and check what your version does with the function, and if it works against the CPU you will be running it on.

基本上,阅读您的 Java 源代码并检查您的版本对函数的作用,如果它对 CPU 起作用,您将在其上运行它。

IBM even suggestsyou use it for performance benchmarking (a 2008 post, but updated).

IBM 甚至建议您将其用于性能基准测试(2008 年的帖子,但已更新)。

回答by Ric Tokyo

The Java 5 documentation also recommends using this method for the same purpose.

Java 5 文档还建议将此方法用于相同目的。

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time.

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

Java 5 API Doc

Java 5 API 文档

回答by starblue

This doesn't seem to be a problem on a Core 2 Duo running Windows XP and JRE 1.5.0_06.

这在运行 Windows XP 和 JRE 1.5.0_06 的 Core 2 Duo 上似乎不是问题。

In a test with three threads I don't see System.nanoTime() going backwards. The processors are both busy, and threads go to sleep occasionally to provoke moving threads around.

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

[EDIT] I would guess that it only happens on physically separate processors, i.e. that the counters are synchronized for multiple cores on the same die.

[编辑] 我猜它只发生在物理上分开的处理器上,即计数器在同一个芯片上的多个内核上是同步的。

回答by mezoid

I did a bit of searching and found that if one is being pedantic then yes it might be considered useless...in particular situations...it depends on how time sensitive your requirements are...

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

Check out this quotefrom the Java Sun site:

查看来自 Java Sun 站点的引用

The real-time clock and System.nanoTime() are both based on the same system call and thus the same clock.

With Java RTS, all time-based APIs (for example, Timers, Periodic Threads, Deadline Monitoring, and so forth) are based on the high-resolution timer. And, together with real-time priorities, they can ensure that the appropriate code will be executed at the right time for real-time constraints. In contrast, ordinary Java SE APIs offer just a few methods capable of handling high-resolution times, with no guarantee of execution at a given time. Using System.nanoTime() between various points in the code to perform elapsed time measurements should always be accurate.

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

使用 Java RTS,所有基于时间的 API(例如,计时器、周期线程、截止日期监控等)都基于高分辨率计时器。而且,连同实时优先级,它们可以确保在正确的时间执行适当的代码以实现实时约束。相比之下,普通的 Java SE API 只提供了几种能够处理高分辨率时间的方法,并不能保证在给定时间执行。在代码中的各个点之间使用 System.nanoTime() 来执行经过的时间测量应该总是准确的。

Java also has a caveat for the nanoTime()method:

Java 还对 nanoTime()方法有一个警告

This method can only be used to measure elapsed time and is not related to any other notion of system or wall-clock time. The value returned represents nanoseconds since some fixed but arbitrary time (perhaps in the future, so values may be negative). This method provides nanosecond precision, but not necessarily nanosecond accuracy. No guarantees are made about how frequently values change. Differences in successive calls that span greater than approximately 292.3 years (263nanoseconds) will not accurately compute elapsed time due to numerical overflow.

此方法只能用于测量经过的时间,与系统或挂钟时间的任何其他概念无关。返回的值表示自某个固定但任意的时间以来的纳秒(可能在未来,因此值可能为负)。此方法提供纳秒精度,但不一定提供纳秒精度。不保证值的更改频率。 由于数值溢出,跨越大约 292.3 年(2 63纳秒)的连续调用之间的差异将无法准确计算经过的时间。

It would seem that the only conclusion that can be drawn is that nanoTime() cannot be relied upon as an accurate value. As such, if you do not need to measure times that are mere nano seconds apart then this method is good enough even if the resulting returned value is negative. However, if you're needing higher precision, they appear to recommend that you use JAVA RTS.

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

So to answer your question...no nanoTime() is not useless....its just not the most prudent method to use in every situation.

所以要回答你的问题......没有 nanoTime() 不是没用......它只是不是在每种情况下使用的最谨慎的方法。

回答by Peter Lawrey

Linux corrects for discrepancies between CPUs, but Windows does not. I suggest you assume System.nanoTime() is only accurate to around 1 micro-second. A simple way to get a longer timing is to call foo() 1000 or more times and divide the time by 1000.

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

回答by Julius Musseau

Disclaimer: I am the developer of this library

免责声明:我是这个库的开发者

You might like this better:

你可能更喜欢这个:

http://juliusdavies.ca/nanotime/

http://juliusdavies.ca/nanotime/

But it copies a DLL or Unix .so (shared object) file into the current user's home directory so that it can call JNI.

但它会将 DLL 或 Unix .so(共享对象)文件复制到当前用户的主目录中,以便它可以调用 JNI。

Some background information is on my site at:

一些背景信息在我的网站上:

http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html

http://juliusdavies.ca/posix_clocks/clock_realtime_linux_faq.html

回答by Yuvi Masory

Absolutely not useless. Timing aficionados correctly point out the multi-core problem, but in real-word applications it is often radically better than currentTimeMillis().

绝对不是没用。计时爱好者正确地指出了多核问题,但在实际应用中,它通常比 currentTimeMillis() 好得多。

When calculating graphics positions in frame refreshes nanoTime() leads to MUCH smoother motion in my program.

在帧刷新中计算图形位置时,nanoTime() 会导致我的程序中的运动更加平滑。

And I only test on multi-core machines.

而且我只在多核机器上测试。

回答by Basil Vandegriend

I have seen a negative elapsedtime reported from using System.nanoTime(). To be clear, the code in question is:

我看到使用 System.nanoTime() 报告的经过时间为负。需要明确的是,有问题的代码是:

    long startNanos = System.nanoTime();

    Object returnValue = joinPoint.proceed();

    long elapsedNanos = System.nanoTime() - startNanos;

and variable 'elapsedNanos' had a negative value. (I'm positive that the intermediate call took less than 293 years as well, which is the overflow point for nanos stored in longs :)

并且变量 'elapsedNanos' 有一个负值。(我肯定中间调用也花了不到 293 年,这是存储在 longs 中的 nanos 的溢出点:)

This occurred using an IBM v1.5 JRE 64bit on IBM P690 (multi-core) hardware running AIX. I've only seen this error occur once, so it seems extremely rare. I do not know the cause - is it a hardware-specific issue, a JVM defect - I don't know. I also don't know the implications for the accuracy of nanoTime() in general.

这是在运行 AIX 的 IBM P690(多核)硬件上使用 IBM v1.5 JRE 64 位发生的。我只看到这个错误发生一次,所以它似乎非常罕见。我不知道原因 - 是特定于硬件的问题还是 JVM 缺陷 - 我不知道。我也不知道一般而言对 nanoTime() 准确性的影响。

To answer the original question, I don't think nanoTime is useless - it provides sub-millisecond timing, but there is an actual (not just theoretical) risk of it being inaccurate which you need to take into account.

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

回答by blais

No need to debate, just use the source. Here, SE 6 for Linux, make your own conclusions:

无需争论,直接使用来源。在这里,适用于 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;
  }
}