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