System.nanotime运行缓慢?

发布于 2024-08-07 23:36:00 字数 1474 浏览 5 评论 0原文

我的一个朋友向我展示了他所做的一些事情,而我却无法解释这是如何发生的:他正在使用 System.nanotime 来计时,并且它每秒都会向用户提供更新以告诉用户多少时间已经过去(这部分是 Thread.sleep(1000)),而且似乎花了很长时间(等待 10 秒的事情大约需要 3 分钟才能完成)。我们尝试使用毫秒来查看已经过去了多少时间:它打印每秒过去了多少纳米时间,我们看到每一秒,纳米时间每秒移动大约 40-50 毫秒。

我检查了与 System.nanotime 和 Java 相关的错误,但似乎我能找到的唯一涉及纳米时间的东西突然 大幅增加然后停止。我还根据我在另一个问题中读到的内容浏览了此博客文章,但是没有任何可能导致它的东西。

显然,可以通过使用毫秒来解决这种情况;有很多解决方法,但我很好奇的是,除了系统时钟的硬件问题或至少CPU拥有的最准确的时钟之外是否还有其他问题(因为这就是System.nanotime似乎使用的)这会导致它像这样一直运行缓慢吗?

long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true), 
//but it illustrates the point
while(true) {
    Thread.sleep(1000);
    long currentNano = System.nanoTime();
    long currentMili = System.currentTimeMillis();
    double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
    double secondsMili = ((double) (currentMili - initialMili))/1000D;
    System.out.println(secondsNano);
    System.out.println(secondsMili);
}

SecondNano 将打印 0.04 的内容,而 SecondsMili 将打印非常接近 1 的内容。

看起来沿着这条线的错误已在 Sun 的 bug 数据库,但他们将其作为重复项关闭,但他们的链接不会转到现有的 bug。这似乎是非常特定于系统的,所以我越来越确定这是一个硬件问题。

One of my friends showed me something he had done, and I was at a serious loss to explain how this could have happened: he was using a System.nanotime to time something, and it gave the user an update every second to tell how much time had elapsed (it Thread.sleep(1000) for that part), and it took seemingly forever (something that was waiting for 10 seconds took roughly 3 minutes to finish). We tried using millitime in order to see how much time had elapsed: it printed how much nanotime had elapsed every second, and we saw that for every second, the nanotime was moving by roughly 40-50 milliseconds every second.

I checked for bugs relating to System.nanotime and Java, but it seemed the only things I could find involved the nanotime suddenly greatly increasing and then stopping. I also browsed this blog entry based on something I read in a different question, but that didn't have anything that may cause it.

Obviously this could be worked around for this situation by just using the millitime instead; there are lots of workarounds to this, but what I'm curious about is if there's anything other than a hardware issue with the system clock or at least whatever the most accurate clock the CPU has (since that's what System.nanotime seems to use) that could cause it to run consistently slow like this?

long initialNano = System.nanoTime();
long initialMili = System.currentTimeMillis();
//Obviously the code isn't actually doing a while(true), 
//but it illustrates the point
while(true) {
    Thread.sleep(1000);
    long currentNano = System.nanoTime();
    long currentMili = System.currentTimeMillis();
    double secondsNano = ((double) (currentNano - initialNano))/1000000000D;
    double secondsMili = ((double) (currentMili - initialMili))/1000D;
    System.out.println(secondsNano);
    System.out.println(secondsMili);
}

secondsNano will print something along the lines of 0.04, whereas secondsMili will print something very close to 1.

It looks like a bug along this line has been reported at Sun's bug database, but they closed it as a duplicate, but their link doesn't go to an existing bug. It seems to be very system-specific, so I'm getting more and more sure this is a hardware issue.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

呢古 2024-08-14 23:36:00

...他使用 System.nanotime 使程序在执行某些操作之前等待,并且...

您能给我们展示一些代码来准确演示他在做什么吗?是否是某种奇怪的繁忙循环,如下所示:

long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }

如果是,那么这不是让程序暂停一段时间的正确方法。使用 Thread.sleep(...) 来使程序等待指定的毫秒数。

... he was using a System.nanotime to cause the program to wait before doing something, and ...

Can you show us some code that demonstrates exactly what he was doing? Was it some strange kind of busy loop, like this:

long t = System.nanoTime() + 1000000000L;
while (System.nanoTime() < t) { /* do nothing */ }

If yes, then that's not the right way to make your program pause for a while. Use Thread.sleep(...) instead to make the program wait for a specified number of milliseconds.

心奴独伤 2024-08-14 23:36:00

您是否意识到您正在使用的循环运行时间并不正好是 1 秒?首先,Thread.sleep() 不能保证准确,并且循环中的其余代码确实需要一些时间来执行(nanoTime() 和 currentTimeMillis() 实际上可能非常慢,具体取决于底层实现)。其次,System.currentTimeMillis() 也不能保证准确(它仅在某些操作系统和硬件组合上每 50 毫秒更新一次)。您还提到上面不准确到 40-50ms,然后继续说 0.004s,实际上只有 4ms。

我建议您将 System.out.println() 更改为:

System.out.println(secondsNano - secondsMili);

这样,您将能够看到两个时钟每秒的差异有多大。我让它在我的笔记本电脑上运行了大约 12 个小时,结果慢了 1.46 秒(快,不慢)。这表明两个时钟存在一定的漂移。

我认为 currentTimeMillis() 方法在很长一段时间内提供更准确的时间,但 nanoTime() 具有更高的分辨率,并且有利于计时代码或在短时间内提供亚毫秒计时。

You do realise that the loop you are using doesn't take exactly 1 second to run? Firstly Thread.sleep() isn't guaranteed to be accurate, and the rest of the code in the loop does take some time to execute (Both nanoTime() and currentTimeMillis() actually can be quite slow depending on the underlying implementation). Secondly, System.currentTimeMillis() is not guaranteed to be accurate either (it only updates every 50ms on some operating system and hardware combinations). You also mention it being inaccurate to 40-50ms above and then go on to say 0.004s which is actually only 4ms.

I would recommend you change your System.out.println() to be:

System.out.println(secondsNano - secondsMili);

This way, you'll be able to see how much the two clocks differ on a second-by-second basis. I left it running for about 12 hours on my laptop and it was out by 1.46 seconds (fast, not slow). This shows that there is some drift in the two clocks.

I would think that the currentTimeMillis() method provides a more accurate time over a large period of time, yet nanoTime() has a greater resolution and is good for timing code or providing sub-millisecond timing over short time periods.

思慕 2024-08-14 23:36:00

我也遇到过同样的问题。除了我的情况之外,它更明显。

通过这个简单的程序:

public class test {
    public static void main(String[] args) {
        while (true) {
            try { 
                Thread.sleep(1000); 
            } 
            catch (InterruptedException e) { 
            }

            OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
        }
    }

    static long nanoTimeMillis() {
        return Math.round(System.nanoTime() / 1000000.0);
    }
}

我得到以下结果:

13:05:16:380 main:  1288199116375   61530042
13:05:16:764 main:  1288199117375   61530438
13:05:17:134 main:  1288199118375   61530808
13:05:17:510 main:  1288199119375   61531183
13:05:17:886 main:  1288199120375   61531559

nanoTime 显示每秒仅经过约 400 毫秒。

I've experienced the same problem. Except in my case, it is more pronounced.

With this simple program:

public class test {
    public static void main(String[] args) {
        while (true) {
            try { 
                Thread.sleep(1000); 
            } 
            catch (InterruptedException e) { 
            }

            OStream.out("\t" + System.currentTimeMillis() + "\t" + nanoTimeMillis());
        }
    }

    static long nanoTimeMillis() {
        return Math.round(System.nanoTime() / 1000000.0);
    }
}

I get the following results:

13:05:16:380 main:  1288199116375   61530042
13:05:16:764 main:  1288199117375   61530438
13:05:17:134 main:  1288199118375   61530808
13:05:17:510 main:  1288199119375   61531183
13:05:17:886 main:  1288199120375   61531559

The nanoTime is showing only ~400ms elapsed for each second.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文