在一次会议上,有人告诉我这DateTime.Now
会导致 IO 阻塞,这是我从未停止考虑的事情。如果是这样,为什么?
3 回答
好吧,考虑到
在ILSpy上使用mscorelib
我们可以发现 ,DateTime.Now
以这种方式出现:
public static DateTime Now
{
get
{
DateTime utcNow = DateTime.UtcNow;
bool isAmbiguousDst = false;
long ticks = TimeZoneInfo.GetDateTimeNowUtcOffsetFromUtc(utcNow, out isAmbiguousDst).Ticks;
long num = utcNow.Ticks + ticks;
if (num > 3155378975999999999L)
{
return new DateTime(3155378975999999999L, DateTimeKind.Local);
}
if (num < 0L)
{
return new DateTime(0L, DateTimeKind.Local);
}
return new DateTime(num, DateTimeKind.Local, isAmbiguousDst);
}
}
该函数GetDateTimeNowUtcOffsetFromUtc
如下所示:
internal static TimeSpan GetDateTimeNowUtcOffsetFromUtc(DateTime time, out bool isAmbiguousLocalDst)
{
isAmbiguousLocalDst = false;
TimeZoneInfo.OffsetAndRule oneYearLocalFromUtc = TimeZoneInfo.GetOneYearLocalFromUtc(time.Year);
TimeSpan timeSpan = oneYearLocalFromUtc.offset;
if (oneYearLocalFromUtc.rule != null)
{
bool isDaylightSavingsFromUtc = TimeZoneInfo.GetIsDaylightSavingsFromUtc(time, time.Year, oneYearLocalFromUtc.offset, oneYearLocalFromUtc.rule, out isAmbiguousLocalDst);
timeSpan += (isDaylightSavingsFromUtc ? oneYearLocalFromUtc.rule.DaylightDelta : TimeSpan.Zero);
}
return timeSpan;
}
GetOneYearLocalFromUtc
而是看起来像:
private static TimeZoneInfo.OffsetAndRule GetOneYearLocalFromUtc(int year)
{
if (TimeZoneInfo.s_oneYearLocalFromUtc == null || TimeZoneInfo.s_oneYearLocalFromUtc.year != year)
{
TimeZoneInfo currentOneYearLocal = TimeZoneInfo.GetCurrentOneYearLocal();
TimeZoneInfo.AdjustmentRule rule = (currentOneYearLocal.m_adjustmentRules == null) ? null : currentOneYearLocal.m_adjustmentRules[0];
TimeZoneInfo.s_oneYearLocalFromUtc = new TimeZoneInfo.OffsetAndRule(year, currentOneYearLocal.BaseUtcOffset, rule);
}
return TimeZoneInfo.s_oneYearLocalFromUtc;
}
最终GetCurrentOneYearLocal
看起来像:
private static TimeZoneInfo GetCurrentOneYearLocal()
{
Win32Native.TimeZoneInformation timeZoneInformation = default(Win32Native.TimeZoneInformation);
long num = (long)UnsafeNativeMethods.GetTimeZoneInformation(out timeZoneInformation);
TimeZoneInfo result;
if (num == -1L)
{
result = TimeZoneInfo.CreateCustomTimeZone("Local", TimeSpan.Zero, "Local", "Local");
}
else
{
result = TimeZoneInfo.GetLocalTimeZoneFromWin32Data(timeZoneInformation, false);
}
return result;
}
有趣的功能是GetTimeZoneInformation
,kernel32.dll
在文档中描述如下:
检索当前时区设置。这些设置控制协调世界时 (UTC) 和本地时间之间的转换。
要访问该时间信息,Windows 实际使用了IO
访问权限。不确定这是否可以定义为“阻塞”,但它肯定会访问保存在磁盘上的系统信息,至少是其中的一部分。
到目前为止,没有人回答当前时间的真正来源。我不了解最新的 PC 架构。但几年前,实时时钟是 CPU(南桥)之外芯片的一部分。因此,为了获得时间,您必须对该芯片进行一些 I/O 操作。(这不是磁盘访问,但仍然是 I/O 操作。)
由于当前进程必须等待时钟的响应,因此它阻塞了 I/O。
所以会议上的那个人是对的。
如果您使用诸如工具 DateTime.Now 之类的反射器查看源代码,则调用 Win API GetSystemTimeAsFileTime,然后使用构造函数创建新的 DateTime 对象,该构造函数具有一个 int64 参数,自 0001 年 1 月 1 日 00:00:00.000 起带有刻度。在这里看不到任何可能导致 I/O 阻塞的东西,而且在 GetSystemTimeAsFileTime 文档中也没有提到这一点。