数年前、私は当時、.Net DateTime クラスが約 10 ~ 15 ミリ秒単位でしか変更されていないことに気付きました。これは、ウィンドウ内のスレッド コンテキストの典型的な持続時間であると私が理解していることとたまたま一致します (これが、スレッドがそれより短い時間スリープしない理由です)。そこで公開されている低解像度の Windows クロックは、スレッド コンテキストの切り替え時に正確に更新されますか? コンテキストスイッチを検出するための安価で汚い方法として使用できますか?
2 に答える
In fact, I'll go with an actual answer:
Are the low resolution windows clocks exposed there really updated precisely at thread context switches?
No - you've got it backwards. The low-resolution Windows clock MAY precipitate a context-change, eg. if an API call with a timeout times out, or a Sleep() call expires.
Can they be used as a cheap and dirty way to detect context switches?
No, because context-switches may not happen on every timer interrupt and happen often upon all the other hardware interrupts and API calls.
いくつかの無効な、または少なくとも不当な仮定を行います。
DateTime.Now
まず、更新に 15 ミリ秒という .NET の制限は Windows の制限であると想定しています。そうかもしれませんが、そうでないかもしれません。
Thread.Sleep()
の解像度が何らかの形で に関連していると仮定していますDateTime.Now
。そうではありません。また、15 ミリ秒の最小スリープが Windows の制限であると想定しています。そうではありません。
また、このステートメントの最後の部分:
これは、ウィンドウ内のスレッド コンテキストの典型的な持続時間であると私が理解していることとたまたま一致します (これが、スレッドがそれより短い時間スリープしない理由です)。
完全に嘘です。スレッドは、そのタイムスライスの残りをあきらめることができます。つまり、その間に別のスレッドを実行するようにスケジュールできます。.NET プログラムであっても、スレッドは15 ミリ秒未満スリープすることがあります。
さらに言えば、DateTime.Now
コンテキストの切り替えに使用されるメカニズムは、ほとんど完全に無関係です。クラスがフィールドを維持せず、要求時に経過時間を計算するのDateTime.Now
とほぼ同じように、要求した場合を除いて、によって返される値が更新されない可能性があります。Stopwatch
Elapsed
いいえ、クロックを使用してコンテキスト スイッチを検出することはできません。
そして、DateTime.Now
15 ミリ秒の分解能という神話は誤りであることが判明しました。このプログラムは、次のことを示しています。
var results = new List<double>();
var startTime = DateTime.Now;
var endTime = startTime.AddSeconds(10);
var lastTime = startTime;
var nowTime = startTime;
while (nowTime < endTime)
{
nowTime = DateTime.Now;
if (nowTime != lastTime)
{
results.Add((nowTime - lastTime).TotalMilliseconds);
lastTime = nowTime;
}
}
Console.WriteLine("Total changes = {0}", results.Count);
var avg = results.Average();
var min = results.Min();
var max = results.Max();
Console.WriteLine("Min: {0}, Max: {1}, Avg: {2}", min, max, avg);
このプログラムはDateTime.Now
10 秒間のタイトなループをチェックインし、戻り値が変化するたびに項目をリストに追加します。私の典型的な実行では、次のような出力が得られます。
Total changes = 9980
Min: 0.9999, Max: 19.998, Avg: 1.00210418837676
したがって、10,000 ミリ秒で 9,980 回の更新が行われました。ミリ秒ごとに更新されなかったのは一度だけだったようです。それはおそらく、その間にスレッドがスワップアウトされたためです。
非常に頻繁に私は得る:
Total changes = 10000
Min: 1, Max: 1, Avg: 1
つまり、クロックはミリ秒ごとに更新されます。