3

在一次会议上,有人告诉我这DateTime.Now会导致 IO 阻塞,这是我从未停止考虑的事情。如果是这样,为什么?

4

3 回答 3

5

好吧,考虑到

在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;
}

有趣的功能是GetTimeZoneInformationkernel32.dll在文档中描述如下:

检索当前时区设置。这些设置控制协调世界时 (UTC) 和本地时间之间的转换。

要访问该时间信息,Windows 实际使用了IO访问权限。不确定这是否可以定义为“阻塞”,但它肯定会访问保存在磁盘上的系统信息,至少是其中的一部分。

于 2012-06-05T15:31:09.193 回答
4

到目前为止,没有人回答当前时间的真正来源。我不了解最新的 PC 架构。但几年前,实时时钟是 CPU(南桥)之外芯片的一部分。因此,为了获得时间,您必须对该芯片进行一些 I/O 操作。(这不是磁盘访问,但仍然是 I/O 操作。)

由于当前进程必须等待时钟的响应,因此它阻塞了 I/O。

所以会议上的那个人是对的。

于 2012-06-05T17:51:30.810 回答
2

如果您使用诸如工具 DateTime.Now 之类的反射器查看源代码,则调用 Win API GetSystemTimeAsFileTime,然后使用构造函数创建新的 DateTime 对象,该构造函数具有一个 int64 参数,自 0001 年 1 月 1 日 00:00:00.000 起带有刻度。在这里看不到任何可能导致 I/O 阻塞的东西,而且在 GetSystemTimeAsFileTime 文档中也没有提到这一点。

于 2012-06-05T15:22:25.743 回答