108

N 時間ごとに実行される Windows サービスを作成する必要があります。
問題は、
どのタイマー コントロールを使用すればよいSystem.Timers.Timerか、またはSystem.Threading.Timer1 つを使用するかということです。それは何かに影響を与えますか?

System.Timers.TimerWindows サービスの動作が正しくないという証拠をたくさん聞いたので質問しています。
ありがとうございました。

4

6 に答える 6

118

System.Timers.Timerとの両方System.Threading.Timerがサービスに対して機能します。

回避したいタイマーはSystem.Web.UI.TimerSystem.Windows.Forms.Timerで、それぞれ ASP アプリケーションと WinForms 用です。これらを使用すると、作成しているアプリケーションの種類に実際には必要のない追加のアセンブリがサービスによって読み込まれます。

次の例のように使用System.Timers.Timerします (また、Tim Robinson の回答で述べられているように、ガベージ コレクションを防ぐためにクラス レベルの変数を使用していることを確認してください)。

using System;
using System.Timers;

public class Timer1
{
    private static System.Timers.Timer aTimer;

    public static void Main()
    {
        // Normally, the timer is declared at the class level,
        // so that it stays in scope as long as it is needed.
        // If the timer is declared in a long-running method,  
        // KeepAlive must be used to prevent the JIT compiler 
        // from allowing aggressive garbage collection to occur 
        // before the method ends. (See end of method.)
        //System.Timers.Timer aTimer;

        // Create a timer with a ten second interval.
        aTimer = new System.Timers.Timer(10000);

        // Hook up the Elapsed event for the timer.
        aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);

        // Set the Interval to 2 seconds (2000 milliseconds).
        aTimer.Interval = 2000;
        aTimer.Enabled = true;

        Console.WriteLine("Press the Enter key to exit the program.");
        Console.ReadLine();

        // If the timer is declared in a long-running method, use
        // KeepAlive to prevent garbage collection from occurring
        // before the method ends.
        //GC.KeepAlive(aTimer);
    }

    // Specify what you want to happen when the Elapsed event is 
    // raised.
    private static void OnTimedEvent(object source, ElapsedEventArgs e)
    {
        Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
    }
}

/* This code example produces output similar to the following:

Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
 */

を選択System.Threading.Timerした場合、次のように使用できます。

using System;
using System.Threading;

class TimerExample
{
    static void Main()
    {
        AutoResetEvent autoEvent     = new AutoResetEvent(false);
        StatusChecker  statusChecker = new StatusChecker(10);

        // Create the delegate that invokes methods for the timer.
        TimerCallback timerDelegate = 
            new TimerCallback(statusChecker.CheckStatus);

        // Create a timer that signals the delegate to invoke 
        // CheckStatus after one second, and every 1/4 second 
        // thereafter.
        Console.WriteLine("{0} Creating timer.\n", 
            DateTime.Now.ToString("h:mm:ss.fff"));
        Timer stateTimer = 
                new Timer(timerDelegate, autoEvent, 1000, 250);

        // When autoEvent signals, change the period to every 
        // 1/2 second.
        autoEvent.WaitOne(5000, false);
        stateTimer.Change(0, 500);
        Console.WriteLine("\nChanging period.\n");

        // When autoEvent signals the second time, dispose of 
        // the timer.
        autoEvent.WaitOne(5000, false);
        stateTimer.Dispose();
        Console.WriteLine("\nDestroying timer.");
    }
}

class StatusChecker
{
    int invokeCount, maxCount;

    public StatusChecker(int count)
    {
        invokeCount  = 0;
        maxCount = count;
    }

    // This method is called by the timer delegate.
    public void CheckStatus(Object stateInfo)
    {
        AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
        Console.WriteLine("{0} Checking status {1,2}.", 
            DateTime.Now.ToString("h:mm:ss.fff"), 
            (++invokeCount).ToString());

        if(invokeCount == maxCount)
        {
            // Reset the counter and signal Main.
            invokeCount  = 0;
            autoEvent.Set();
        }
    }
}

両方の例は、MSDN ページからのものです。

于 2008-10-29T13:06:36.053 に答える
37

これにはサービスを使用しないでください。通常のアプリケーションを作成し、スケジュールされたタスクを作成して実行します。

これは、一般的に行われているベスト プラクティスです。 ジョン・ギャロウェイは私に同意します。または、その逆かもしれません。 いずれにせよ、Windows サービスを作成してタイマーで実行される断続的なタスクを実行することはベスト プラクティスではありません。

「タイマーを実行する Windows サービスを作成している場合は、ソリューションを再評価する必要があります。」

–Jon Galloway、ASP.NET MVC コミュニティ プログラム マネージャー、著者、パートタイムのスーパーヒーロー

于 2008-10-29T13:47:50.183 に答える
7

どちらでも問題なく動作するはずです。実際、System.Threading.Timer は System.Timers.Timer を内部的に使用します。

そうは言っても、System.Timers.Timer を誤用するのは簡単です。Timer オブジェクトを変数に格納しないと、ガベージ コレクションが発生する可能性があります。その場合、タイマーは起動しなくなります。Dispose メソッドを呼び出してタイマーを停止するか、もう少し優れたラッパーである System.Threading.Timer クラスを使用します。

これまでにどのような問題が発生しましたか?

于 2008-10-29T13:03:31.303 に答える
2

別のアプローチを検討するのが最善かもしれないという以前のコメントに同意します。私の提案は、コンソール アプリケーションを作成し、Windows スケジューラを使用することです。

この意志:

  • スケジューラの動作を複製する配管コードを減らす
  • アプリケーション コードから抽象化されたすべてのスケジューリング ロジックを使用して、スケジューリング動作 (週末のみに実行するなど) に関してより大きな柔軟性を提供します。
  • 構成ファイルなどで構成値を設定する必要なく、パラメーターのコマンド ライン引数を利用します。
  • 開発中のデバッグ/テストがはるかに簡単
  • サポート ユーザーがコンソール アプリケーションを直接呼び出して実行できるようにします (たとえば、サポート状況で役立ちます)。
于 2008-10-29T14:27:57.653 に答える
1

すでに述べたように、両方とも機能System.Threading.TimerSystem.Timers.Timerます。2 つの大きな違いはSystem.Threading.Timer、もう一方の周りにラッパーがあることです。

System.Threading.TimerSystem.Timers.Timerすべての例外を飲み込みながら、より多くの例外処理を 行います。

これは過去に大きな問題を引き起こしたので、常に「System.Threading.Timer」を使用し、例外をうまく処理していました。

于 2013-05-15T13:26:25.413 に答える