65

今天我做了一点快速的基准测试来测试System.nanoTime()和的速度性能System.currentTimeMillis()

long startTime = System.nanoTime();

for(int i = 0; i < 1000000; i++) {
  long test = System.nanoTime();
}

long endTime = System.nanoTime();

System.out.println("Total time: "+(endTime-startTime));

这是结果:

System.currentTimeMillis(): average of 12.7836022 / function call
System.nanoTime():          average of 34.6395674 / function call

为什么跑步速度差异如此之大?

基准系统:

Java 1.7.0_25
Windows 8 64-bit
CPU: AMD FX-6100
4

5 回答 5

69

这个甲骨文博客

System.currentTimeMillis()使用 GetSystemTimeAsFileTime 方法实现,该方法本质上只是读取 Windows 维护的低分辨率时间值。读取这个全局变量自然很快——根据报告的信息,大约需要 6 个周期。

System.nanoTime()使用 QueryPerformanceCounter/ QueryPerformanceFrequency API(如果可用,否则返回currentTimeMillis*10^6). QueryPerformanceCounter(QPC)) 实现,具体取决于其运行的硬件。通常,它将使用可编程间隔定时器 (PIT) 或 ACPI 电源管理定时器 (PMT),或 CPU 级时间戳计数器 (TSC)。访问 PIT/PMT 需要执行慢速 I/O 端口指令,因此 QPC 的执行时间约为微秒。相比之下,读取 TSC 是在大约 100 个时钟周期(从芯片中读取 TSC 并将其转换为基于工作频率的时间值)。

也许这回答了这个问题。这两种方法使用不同数量的时钟周期,从而导致后一种速度较慢。

在结论部分的该博客中进一步:

如果您对测量/计算经过的时间感兴趣,请始终使用 System.nanoTime()。在大多数系统上,它会给出微秒级的分辨率。但请注意,此调用在某些平台上也可能需要几微秒才能执行。

于 2013-09-27T13:49:22.333 回答
24

大多数操作系统(您没有提到您使用的是哪一个)都有一个内存计数器/时钟,可提供毫秒精度(或接近该精度)。对于纳秒精度,大多数必须读取硬件计数器。与硬件通信比读取内存中已经存在的一些值要慢。

于 2013-09-27T13:47:30.567 回答
5

它可能仅适用于 Windows。请参阅此对类似问题的答案。

基本上,System.currentTimeMillis()只是读取一个由 Windows 维护的全局变量(这就是它具有低粒度的原因),而System.nanoTime()实际上必须进行 IO 操作。

于 2013-09-27T13:49:14.363 回答
1

你是在 Windows 上测量的,不是吗。我在 2008 年完成了这个练习。nanoTime 在 Windows 上比 currentTimeMillis 慢。我记得,在 Linux 上,nanotime 比 currentTimeMillis 快,而且肯定比在 Windows 上快。

需要注意的重要一点是,如果您尝试测量多个亚毫秒操作的聚合,则必须使用 nanotime,就好像操作在不到 1/1000 秒的代码中完成一样,比较 currentTimeMillis 将显示操作是瞬时的所以其中的 1,000 个仍然是瞬时的。您可能想要做的是使用 nanotime 然后四舍五入到最接近的毫秒,因此如果一个操作花费了 8000 纳秒,它将被计为 1 毫秒,而不是 0。

于 2014-02-06T14:45:24.770 回答
0

您可能想要做的是使用 nanotime 然后四舍五入到最接近的毫秒,因此如果一个操作花费了 8000 纳秒,它将被计为 1 毫秒,而不是 0。

算术笔记:

8000 纳秒是 8 微秒是 0.008 毫秒。四舍五入将把它带到 0 毫秒。

于 2015-08-15T22:50:23.350 回答