【问题标题】:Is DateTime.Now an I/O bound operation?DateTime.Now 是 I/O 绑定操作吗?
【发布时间】:2016-06-05 15:16:09
【问题描述】:

当您致电DateTime.Now 时会发生什么?

我按照 Reflector 中的属性代码,它似乎将当前语言环境的时区偏移添加到 UtcNow。跟着UTCNow 一步步引导我,终于到了 Win32 API 调用。

我反省了一下,问了a related question,但还没有得到满意的答复。从目前对该问题的评论中的链接,我推断有一个硬件单元可以保持时间。但我也想知道它保存时间的单位以及它是否使用 CPU 将时间转换为人类可读的单位。这将阐明日期和时间信息的检索是否受 I/O 限制或计算限制。

【问题讨论】:

  • IO 和计算边界是非常未定义的术语。您能否说明您感兴趣的属性或想要实现的目标?
  • 我认为引入日期是 I/O 绑定的,使用 DateTime.Now 转换它(它返回可读值对吗?)是计算绑定的。那么,他们俩呢?
  • @usr 由于我对您的问题以及 I/O 和计算的概念与您的问题所表明的深度的理解有限,我无法回答您的问题。我不确定我想要什么。我只想知道会发生什么,这样我就可以计划下次如何拨打DateTime.Now,这样我就不会阻止它,如果有的话。这只是我最近思考的事情之一。
  • @Ali 我想你是对的。不过,我想要更准确的细节。
  • 如果您告诉我们它调用了哪个 Win32 API,您可以帮助我们为您提供更好的答案。逗弄。

标签: c# .net datetime


【解决方案1】:

您对这个问题深陷无证领域。时间由内核提供:底层原生 API 调用为NtQuerySystemTime()。这确实在各个 Windows 版本中都得到了修改 - Windows 8 特别严重地改变了底层实现,具有明显的副作用。

它本质上是 I/O 限制的:时间由 RTC(实时时钟)维护,它曾经是专用芯片,但现在集成在芯片组中。但是有非常有力的证据表明它在实践中不受 I/O 限制。时间更新与时钟中断同步,因此中断处理程序很可能会读取 RTC,并且您会获得该值的副本。修改 timeBeginPeriod() 时可以看到的东西。

当您对其进行分析时,您会发现它在 Windows 10 上只需要大约 7 纳秒 - 完全快到无法绑定 I/O。

【讨论】:

  • 它在内核中,RTC 是可能的中断源。也严重影响线程调度程序,上下文切换以中断率发生。 Sleep() 永远不会比速率更准确的一个基本原因。更深入的未记录细节,不应影响您的编码方式。
  • 实际上,我相信 RTC 仅在启动时使用,然后内核使用其他一些计时器(可能是主 CPU 时钟)自行保持时间。
  • @AndréBorie HPET 使用不同的计时机制,如今在硬件中。如果不可用(旧硬件),则 RTC 和 CPU 计时器的组合。 DateTime.NowSleep 之类的 AFAIK 使用 RTC。您实际上可以在一个循环中对其进行测试,并查看值以 (iirc) 15 ms 的间隔跳跃,这是 RTC 的典型值。
  • 如果你要上课以访问 RTC 作为 I/O,你会在哪里停下来?访问内存也是 I/O 吗?
  • 我已经对 (benchmarkdotnet) DateTime.Now 进行了基准测试,在 Windows 10(CPU E3-1270 v5 3.60GHz,ProcessorCount=8)上平均耗时不是 7ns,而是 627ns。返回一个缓存值需要 0.3ns。
【解决方案2】:

您似乎担心阻塞。有两种情况需要避免。

  1. 在 UI 线程上,它与延迟有关。不管你做什么(IO 或 CPU),都不会花很长时间。否则它会冻结 UI 线程。 UtcNow 速度超级快,所以不用担心。
  2. 有时,随着负载的增加,非阻塞 IO 被用作扩展吞吐量的一种方式。在这里,唯一的原因是为了节省线程,因为每个线程都消耗大量资源。由于没有异步方式调用UtcNow,所以这个问题没有实际意义。您只需按原样调用即可。

由于 Windows 上的时间通常以 60 Hz 前进,我假设对 UtcNow 的调用从以 60 Hz 写入的内存变量中读取。这使得 CPU 受限。但不管怎样都无所谓。

【讨论】:

  • 有趣!你知道~60HzWindows时间进度的任何文章吗?我用谷歌搜索,但我得到的只是显示器刷新率。
  • 它是 64 Hz,而不是 60。当你使用 SO 时往往是 100 Hz,浏览器会修改它:)
  • 它在现代计算机上变化很大。能源管理和应用程序可以对其进行调整。 SysInternals 开发了一个工具来监控它:technet.microsoft.com/en-us/sysinternals/bb897568.aspx
  • 内置于 Windows,powercfg.exe /energy 非常漂亮。
【解决方案3】:

.NET 依赖于 API。 MSDN 不得不这样说 API:

https://msdn.microsoft.com/de-de/library/windows/desktop/ms724961(v=vs.85).aspx

系统首次启动时,它会将系统时间设置为基于计算机实时时钟的值,然后定期更新时间 [...] GetSystemTime 将时间复制到 SYSTEMTIME [...]

我没有找到可靠的来源来支持我的说法,即它存储为SYSTEMTIME 结构,在其中更新,并在调用时复制到GetSystemTime 的接收缓冲区中。 NtQuerySystemTime 系统调用的最小逻辑单元是 100ns,但我们在 CLR 的 DateTime 对象中最终得到 1 毫秒。分辨率并不总是相同的。

对于 Linux 上的 Mono,我们或许能够弄清楚这一点,但对于 Windows,鉴于 API 代码本身是不公开的,因此很难解决。所以这里有一个假设:当前时间是内核地址空间中的一个变量。它将由操作系统更新(通常由系统时钟定时器中断,不太频繁地可能来自网络源——文档提到调用者可能不依赖单调行为,因为网络同步可以向后更正当前时间)。操作系统将同步访问以防止并发写入,否则不会是 I/O 开销大的操作。

在最近的计算机上,计时器间隔不再固定,可以由 BIOS 和操作系统控制。应用程序甚至可以请求更低或更高的时钟频率:https://randomascii.wordpress.com/2013/07/08/windows-timer-resolution-megawatts-wasted

【讨论】:

  • 最小的逻辑单位实际上是 100 纳秒。
  • 好吧,CLR 中有 DateTime.Millisecond 成员,它被记录为“毫秒组件,表示为 0 到 999 之间的值”,_SYSTEMTIME.wMilliseconds 字段被记录为“毫秒。此成员的有效值为 0 到 999"。我们将不得不研究 GetSystemTimePreciseAsFileTimethis 的 ns 甚至 µs,足以单独提出一个问题
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-12-01
  • 2011-09-04
  • 1970-01-01
  • 1970-01-01
  • 2020-09-03
  • 2011-05-10
相关资源
最近更新 更多