【发布时间】: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() 是一种更好的方法,对于将来遇到此问题的其他所有人来说。谢谢大家。