为啥 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)?

Posted

技术标签:

【中文标题】为啥 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)?【英文标题】:Why is System.nanoTime() way slower (in performance) than System.currentTimeMillis()?为什么 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)? 【发布时间】:2013-10-03 20:13:39 【问题描述】:

今天我做了一点快速的基准测试来测试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

【问题讨论】:

Why do System.nanoTime() and System.currentTimeMillis() drift apart so rapidly?的可能重复 这篇文章可能会回答你的问题:***.com/a/5839267/658907 nanoTimecurrentTimeMillis 更精确,这可能是原因。 不同意这是一个重复的问题。这是询问执行速度。另一个问题是关于漂移的问题。也许答案是相似的,但问题不是。 不回答你的问题,但即使是“慢”nanoTime 也只需要 34 纳秒 来执行。我没有看到很多用例如此缓慢以至于成为问题。 【参考方案1】:

可能仅适用于 Windows。有关类似问题,请参阅 this answer。

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

【讨论】:

【参考方案2】:

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

算术笔记:

8000 纳秒是 8 微秒是 0.008 毫秒。四舍五入将花费 0 毫秒。

【讨论】:

【参考方案3】:

来自this Oracle blog:

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()。在大多数系统上,它会给出微秒级的分辨率。但请注意,此调用在某些平台上也可能需要几微秒才能执行

【讨论】:

不错的答案。还有这个网站:stas-blogspot.blogspot.nl/2012/02/… 有人做了一点研究,还展示了不同操作系统上 System.nanoTime 背后的源代码。【参考方案4】:

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

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

【讨论】:

【参考方案5】:

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

【讨论】:

以上是关于为啥 System.nanoTime() 比 System.currentTimeMillis() 慢(在性能上)?的主要内容,如果未能解决你的问题,请参考以下文章

System.nanoTime() 的 Java 时代? [复制]

java的System.currentTimeMillis()和System.nanoTime()

Java性能优化的十条小技巧

System.nanoTime与System.currentTimeMillis的区别

将 System.currentTimeMillis() 与 System.nanoTime() 结合使用是不是合理?

System.nanoTime()和System.currentTimeMillis()性能问题