プログラムを繰り返し(たとえば 2 分ごとに)実行するための Windows サービスとスケジュールされたタスクの長所と短所は何ですか?
ベストアンサー1
アップデート:
私の最初の回答から4年近く経ち、この回答は非常に古くなっています。いちばん上の棚Windows の登場により、サービス開発は簡単になりました。あとは、フェールオーバーをサポートする方法を考えるだけです...
元の回答:
私はWindows Schedulerのファンではありません。ユーザーのパスワードは次のように入力する必要があります。フォロー上記で指摘したように、誰かがそのユーザーのパスワードを変更すると面白いことになります。
Windows Scheduler のもう 1 つの大きな問題点は、バックグラウンド プロセスとしてではなく、対話的に実行されることです。RDP セッション中に 20 分ごとに 15 個の MS-DOS ウィンドウがポップアップ表示されたら、Windows サービスとしてインストールしなかったことを後悔するでしょう。
どちらを選択する場合でも、処理コードをコンソール アプリまたは Windows サービスとは別のコンポーネントに分離することをお勧めします。その後、コンソール アプリケーションからワーカー プロセスを呼び出して Windows スケジューラに接続するか、Windows サービスを使用するかを選択できます。
Windows サービスのスケジュール設定は楽しいものではありません。かなり一般的なシナリオは、定期的に実行したい長時間実行プロセスがあることです。ただし、キューを処理している場合は、同じワーカーの 2 つのインスタンスが同じキューを処理することは望ましくありません。そのため、タイマーを管理して、長時間実行プロセスが割り当てられたタイマー間隔よりも長く実行された場合、既存のプロセスが終了するまで再度開始されないようにする必要があります。
ここまで書いた後、なぜ Thread.Sleep を使わなかったのかと思うかもしれません。Thread.Sleep を使用すると、現在のスレッドが終了するまで実行し続け、その後一時停止間隔が開始され、スレッドはスリープ状態になり、必要な時間が経過すると再び開始されます。すばらしいですね。
次に、インターネット上のあらゆるアドバイスを読み、多くの専門家が、それがいかに悪いプログラミング習慣であるかを説きます。
それで、あなたは頭を掻きながら、何だこれ、保留中のチェックアウトを元に戻す -> はい、間違いない -> 今日の作業をすべて元に戻す...くそ、くそ、くそ....と考えます。
しかし、誰もがこのパターンをくだらないと思うとしても、私はこのパターンが好きです。
シングルスレッド アプローチの OnStart メソッド。
protected override void OnStart (string args) { // Create worker thread; this will invoke the WorkerFunction // when we start it. // Since we use a separate worker thread, the main service // thread will return quickly, telling Windows that service has started ThreadStart st = new ThreadStart(WorkerFunction); workerThread = new Thread(st); // set flag to indicate worker thread is active serviceStarted = true; // start the thread workerThread.Start(); }
コードは別のスレッドをインスタンス化し、それにワーカー関数をアタッチします。次に、スレッドを開始し、OnStart イベントを完了させて、Windows がサービスがハングしていると認識しないようにします。
シングルスレッド アプローチのワーカー メソッド。
/// <summary> /// This function will do all the work /// Once it is done with its tasks, it will be suspended for some time; /// it will continue to repeat this until the service is stopped /// </summary> private void WorkerFunction() { // start an endless loop; loop will abort only when "serviceStarted" // flag = false while (serviceStarted) { // do something // exception handling omitted here for simplicity EventLog.WriteEntry("Service working", System.Diagnostics.EventLogEntryType.Information); // yield if (serviceStarted) { Thread.Sleep(new TimeSpan(0, interval, 0)); } } // time to end the thread Thread.CurrentThread.Abort(); }
シングルスレッド アプローチの OnStop メソッド。
protected override void OnStop() { // flag to tell the worker process to stop serviceStarted = false; // give it a little time to finish any pending work workerThread.Join(new TimeSpan(0,2,0)); }
私は何年もこのようにして多くの Windows サービスを実行してきましたが、うまく機能しています。人々が同意する推奨パターンはまだ見たことがありません。自分にとってうまくいく方法を実行してください。