【问题标题】:Is it possible to make this Java timer have better than ~15 ms resolution?是否有可能使这个 Java 计时器的分辨率优于 ~15 毫秒?
【发布时间】:2014-08-17 03:52:17
【问题描述】:

我已经用 Java 构建了一个计时循环。简单的。我避免使用Thread.sleep(),因为我的线程调度开销使高分辨率延迟变得不可能,因此我使用了以下效率极低的循环并获得了更好的结果:

public static void timerBlockingDelayTest()
{
    long DELAY_TARGET = 5; 
    long t0, t; 

    t0 = System.currentTimeMillis(); 
    while (System.currentTimeMillis() < t0+DELAY_TARGET) {}
    t = System.currentTimeMillis(); 

    long offTargetAmt = Math.abs(t-t0-DELAY_TARGET); 
    System.out.format("Timer loop was off target by %d milliseconds\n",
            offTargetAmt);
}

我知道的事情:操作系统不是实时的,线程调度是操作系统的一时兴起,GC 会导致延迟。

我没有考虑什么?

在我的机器(Windows 7 x64、i5、2.4GHz)上,我可以获得的最佳分辨率约为 15 毫秒。事实上,如果我将DELAY_TARGET 设为 15 的倍数,那么一切都会很好。但是,如果目标时间不接近 15 的倍数,则上面的 offTargetAmt 通常为 ~8 (ms)。

我也知道这个帖子:high resolution timer in java

什么鬼?!正负~8 ms 真的是我能做的最好的吗??!我只是在寻找“是的,这是正确的”或“不,你没有考虑___”的答案。谢谢

更新

使用 System.nanoTime() 似乎有很大的不同。起初我不相信,但这是我比较这两种方法的更新代码。你自己看。

public static void timerBlockingDelayTest()
{
    long DELAY_TARGET_MS = 5; 
    long NS_PER_MS = 1000000; 
    long DELAY_TARGET_NS = DELAY_TARGET_MS * NS_PER_MS; 
    long t0, t; 

    // Using System.currentTimeMillis() 
    t0 = System.currentTimeMillis(); 
    while (System.currentTimeMillis() < t0+DELAY_TARGET_MS) {}
    t = System.currentTimeMillis(); 
    long msOffTarget = Math.abs(t-t0-DELAY_TARGET_MS); 

    // Using System.nanoTime()
    t0 = System.nanoTime(); 
    while (System.nanoTime() < t0+DELAY_TARGET_NS) {}; 
    t = System.nanoTime(); 
    long nsOffTarget = Math.abs(t-t0-DELAY_TARGET_NS); 

    // Compare the two methods
    System.out.format("System.currentTimeMillis() method: "); 
    System.out.format(" - Off by %d ms (%d ns) \n", 
            msOffTarget, msOffTarget*NS_PER_MS); 
    System.out.format("System.nanoTime() method:          "); 
    System.out.format(" - Off by %d ms (%d ns)\n", 
            nsOffTarget/NS_PER_MS, nsOffTarget); 
}

这是一个示例输出:

debug:
System.currentTimeMillis() method:  - Off by 11 ms (11000000 ns) 
System.nanoTime() method:           - Off by 0 ms (109 ns)
BUILD SUCCESSFUL (total time: 0 seconds)

UPDATE 2(希望是最后一次):

呃。 单独衡量量化或不完善的时间函数的性能有点愚蠢。我的意思是我实际上是在单独测量 currentTimeMillis() 的性能,这不是我做过的最聪明的事情。意识到这一点后,我分析了上述两种方法,发现确实 nanoTime() 产生了更好的分辨率。

如果您没有分析器,请使用 nanoTime() 来测量 currentTimeMillis() 循环的持续时间,如下所示:

public static void timerBlockingDelayTest()
{
    long DELAY_TARGET_MS = 5; 
    long NS_PER_MS = 1000000; 
    long DELAY_TARGET_NS = DELAY_TARGET_MS * NS_PER_MS; 
    long t0ms, t0, t; 

    // Using System.currentTimeMillis() 
    t0 = System.nanoTime(); 
    t0ms = System.currentTimeMillis(); 
    while (System.currentTimeMillis() < t0ms+DELAY_TARGET_MS) {}
    t = System.nanoTime(); 
    long nsOffTarget1 = Math.abs(t-t0-DELAY_TARGET_NS); 

    // Using System.nanoTime()
    t0 = System.nanoTime(); 
    while (System.nanoTime() < t0+DELAY_TARGET_NS) {}; 
    t = System.nanoTime(); 
    long nsOffTarget2 = Math.abs(t-t0-DELAY_TARGET_NS); 

    // Compare the two methods
    System.out.format("System.currentTimeMillis() method: "); 
    System.out.format(" - Off by %d ms (%d ns)\n", 
            nsOffTarget1/NS_PER_MS, nsOffTarget1); 
    System.out.format("System.nanoTime() method:          "); 
    System.out.format(" - Off by %d ms (%d ns)\n", 
            nsOffTarget2/NS_PER_MS, nsOffTarget2); 
}

至少这样我是通过相同的参考来测量两个延迟的,这只是稍微智能一些。上面给出了这样的输出:

debug:
System.currentTimeMillis() method:  - Off by 4 ms (4040402 ns)
System.nanoTime() method:           - Off by 0 ms (110 ns)
BUILD SUCCESSFUL (total time: 0 seconds)

结论:使用 nanoTime(),祝你有美好的一天。

【问题讨论】:

  • System.nanotime 会给你更高的分辨率时间:stackoverflow.com/questions/351565/…
  • @JaredLindsey 该链接中的详细信息比链接答案中的要好得多(尽管我还没有看到更好的答案),因为它实际上会抛出降低一些预期的数字。我会赞成一个适当总结/突出上下文中所述资源的答案。
  • 我已经进行了一些分析,很明显使用 nanoTime() 是一种更好的方法,对于将来遇到此问题的其他所有人来说。谢谢大家。

标签: java timer


【解决方案1】:

请改用System.nanoTime。请参阅this answer 了解 nanoTime 和 currentTimeMillis 之间的区别。

【讨论】:

  • 天哪。我不相信……但我现在相信了。哇。我将发布我编辑的代码并显示差异
猜你喜欢
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 2020-02-06
  • 1970-01-01
  • 2012-11-12
  • 1970-01-01
  • 1970-01-01
  • 2011-11-06
相关资源
最近更新 更多