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

興味深い関数はGetTimeZoneInformationであり、kernel32.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が呼び出され、その後、0001 年 1 月 1 日 00:00:00.000 からの目盛りを持つ 1 つの int64 パラメーターを持つコンストラクターを使用して新しい DateTime オブジェクトが作成されます。I/O ブロッキングを引き起こす可能性のあるものはここには表示されません。また、GetSystemTimeAsFileTime のドキュメントにも記載されていません。

于 2012-06-05T15:22:25.743 に答える