1日に実行する操作の数に制限があるループでプロセスを実行しています。この制限に達すると、現在、ループ内の時刻をチェックして、新しい日付かどうかを確認しています。
最善の選択肢は次のとおりです。
- 新しい日付のために毎秒時間をチェックし続けてください
- 真夜中までの秒数を計算し、その時間の長さを眠る
- 他に何かありますか?
1日に実行する操作の数に制限があるループでプロセスを実行しています。この制限に達すると、現在、ループ内の時刻をチェックして、新しい日付かどうかを確認しています。
最善の選択肢は次のとおりです。
このタイプのものにはThread.Sleepを使用しないでください。タイマーを使用して、待機する必要のある時間を計算します。
var now = DateTime.Now;
var tomorrow = now.AddDays(1);
var durationUntilMidnight = tomorrow.Date - now;
var t = new Timer(o=>{/* Do work*/}, null, TimeSpan.Zero, durationUntilMidnight);
/* Do Work */
デリゲートを、指定された間隔で作業を再開するコールバックに置き換えます。
編集:コメントで述べたように、アプリケーションが待機する「経過時間」が実際の時間と一致すると仮定すると、うまくいかない可能性のあることがたくさんあります。このため、タイミングが重要な場合は、より短いポーリング間隔を使用して、作業を実行したい時間に時計が到達したかどうかを確認することをお勧めします。
さらに良いのは、Windowsタスクスケジューラを使用して、目的の時間にタスクを実行することです。これは、コードで自分で実装しようとするよりもはるかに信頼性が高くなります。
Windowsには、まさにこの義務を処理するタスクスケジューラがあります。それがすることになっていることをするためにプログラムを作成してください。次に、それをスケジュールされたタスクとして設定します。
待機する期間を計算して非同期タイマーを実行するだけで、待機中に余分なCPUを消費することを回避できます。
var nextDateStartDateTime = DateTime.Now.AddDays(1).Subtract(DateTime.Now.TimeOfDay);
double millisecondsToWait = (nextDateStartDateTime - DateTime.Now).TotalMilliseconds;
System.Threading.Timer timer = new Timer(
(o) => { Debug.WriteLine("New day comming on"); },
null,
(uint)millisecondsToWait
0);
提供した2つのオプションを検討します。
1日あたり60*60 * 24 = 86,400秒あるため、早期に制限に達した場合は、多くのチェックを行う可能性があります。さらに、ビジーウェイトはCPUサイクルの浪費であり、実行中の他のすべての速度が低下します。
真夜中までの秒数を計算し、その時間だけスリープする必要があります(ただし、スリープパラメータはsではなくmsかかると思うので、簡単な変換が必要になる場合があります)。
編集:
計算してからスリープすることの追加の利点は、ユーザーが時計を変更して制限を回避したい場合、それができないことです(深夜の時計の読み取りは、継続的なチェックの場合のようにプロセスをウェイクアップしないため)。ただし、プログラムが内部でどのように機能するかをよりよく理解すると、ユーザーは、操作の制限に達するたびに時計をほぼ真夜中に変更して、スレッドを数分または数秒でウェイクアップさせることができます。これは、最初の提案で実行できるよりも複雑な悪用ですが、実行することはできます。
これが私が明日午前6時までスレッドをスリープさせる方法です
minutesToSleep = (int)(new DateTime(DateTime.Now.AddDays(1).Year, DateTime.Now.AddDays(1).Month, DateTime.Now.AddDays(1).Day, 6, 0, 0) - DateTime.Now).TotalMinutes;
Console.WriteLine("Sleeping for {0} minutes (until tomorrow 6AM)", minutesToSleep);