web-dev-qa-db-ja.com

System.Timers.Timer / Threading.Timerと、Whileループを含むスレッド+定期的なタスクのThread.Sleep

私のアプリケーションでは、「兄弟」アプリケーションに定期的にハートビートを送信する必要があります。

これは、System.Timers.Timer/Threading.Timerを使用するか、whileループとThread.Sleepでスレッドを使用する方が適切ですか?

ハートビート間隔は1秒です。

while(!exit)
{
   //do work
   Thread.Sleep(1000);
}

または

myTimer.Start( () => { 
                       //do work 
                      }, 1000); //pseudo code (not actual syntax)...
44
Alan

System.Threading.Timer には私の投票があります。

System.Timers.Timerは、サーバーベースの(ユーザーが実行するのではなく、ホストマシン上でサーバー/サービスとしてコードが実行されている)タイマー機能で使用するためのものです。

.NETでより堅牢なタイマーメカニズムが存在することを考えると、WhileループとThread.Sleepコマンドを含むスレッドは、本当に悪い考えです。

32
Justin Niessner

サーバータイマー は、スリープ状態のスレッドとは異なる生き物です。

1つには、スレッドの優先順位と他に何が実行されているかに基づいて、スリープ状態のスレッドが起こされたり、要求された間隔で実行されるようにスケジュールされたりする場合があります。間隔が十分に長く、スケジューリングの精度が重要でない場合は、Thread.Sleep()が適切な選択です。

一方、タイマーは任意のスレッドでイベントを発生させることができるため、スケジューリング機能を向上させることができます。ただし、タイマーを使用するコストは、コードが少し複雑になります。また、タイマーイベントが発生するロジックを実行するスレッドを制御できない場合があるという事実です。ドキュメントから:

サーバーベースのタイマーは、マルチスレッド環境のワーカースレッドで使用するように設計されています。サーバータイマーは、発生したElapsedイベントを処理するためにスレッド間を移動できるため、Windowsタイマーよりも時間どおりにイベントを発生させることができます。

別の考慮事項は、タイマーがThreadPoolスレッドでElapsedデリゲートを呼び出すことです。ロジックの時間や複雑さによっては、スレッドプールで実行したくない場合があります-専用スレッドが必要な場合があります。タイマーのもう1つの要因は、処理に十分な時間がかかる場合、タイマーイベントが別のスレッドで(同時に)再度発生する可能性があることです。これは、実行中のコードが同時実行を目的としていないか、構造化されていない場合に問題になる可能性があります。

Server Timersを「Windows Timers」と混同しないでください。後者は通常、ウィンドウに配信できるWM_TIMERメッセージを参照します。これにより、アプリはスリープせずにメインスレッドで時間処理にスケジュールを設定して応答できます。ただし、Windowsタイマーは 低レベルタイミング用のWin API を参照することもできます(WM_TIMERとは異なります)。

23
LBushkin

どちらでもない:)

睡眠は一般的には眉をひそめられます(残念ながら、詳細を思い出せませんが、1つには不可避な「ブロック」です)、Timersには多くの荷物が付属しています。できれば、System.Threading.AutoResetEvent など

// initially set to a "non-signaled" state, ie will block
// if inspected
private readonly AutoResetEvent _isStopping = new AutoResetEvent (false);

public void Process()
{
    TimeSpan waitInterval = TimeSpan.FromMilliseconds (1000);

    // will block for 'waitInterval', unless another thread,
    // say a thread requesting termination, wakes you up. if
    // no one signals you, WaitOne returns false, otherwise
    // if someone signals WaitOne returns true
    for (; !_isStopping.WaitOne (waitInterval); )
    {
        // do your thang!
    }
}

AutoResetEvent(またはそのいとこManualResetEvent)を使用すると、スレッドセーフシグナリングを備えた真のブロックが保証されます(上記の適切な終了など)。最悪の場合、Sleepの代わりに使用することをお勧めします

お役に立てれば :)

21
johnny g

実際にスケーリングする唯一のタイマー実装はSystem.Threading.Timerであることがわかりました。予定された項目の数が少なくない場合、他のすべての実装はかなり偽物に見えます。

1
spender