3

次のように処理する必要がある C# コンソール バッチ アプリケーションに最適なタイマー アプローチはどれですか。

  1. データソースに接続する
  2. タイムアウトが発生するか、処理が完了するまでバッチを処理します。「データソースで何かをする」
  3. コンソール アプリを正常に停止します。

関連する質問: C# コンソール アプリケーションにタイマーを追加する方法

4

3 に答える 3

5

これが完全なコンソール アプリで申し訳ありませんが、ここに完全なコンソール アプリがあります。繰り返しますが、私は非常に多くのコードをお詫びしますが、他の誰もが「ああ、あなたがしなければならないのはそれをするだけです」という答えを与えているようです:)

using System;
using System.Collections.Generic;
using System.Threading;

namespace ConsoleApplication1
{
    class Program
    {
        static List<RunningProcess> runningProcesses = new List<RunningProcess>();

        static void Main(string[] args)
        {
            Console.WriteLine("Starting...");

            for (int i = 0; i < 100; i++)
            {
                DoSomethingOrTimeOut(30);
            }

            bool isSomethingRunning = false;

            do
            {
                foreach (RunningProcess proc in runningProcesses)
                {
                    // If this process is running...
                    if (proc.ProcessThread.ThreadState == ThreadState.Running)
                    {
                        isSomethingRunning = true;

                        // see if it needs to timeout...
                        if (DateTime.Now.Subtract(proc.StartTime).TotalSeconds > proc.TimeOutInSeconds)
                        {
                            proc.ProcessThread.Abort();
                        }
                    }
                }
            }
            while (isSomethingRunning);

            Console.WriteLine("Done!");    

            Console.ReadLine();
        }

        static void DoSomethingOrTimeOut(int timeout)
        {
            runningProcesses.Add(new RunningProcess
            {
                StartTime = DateTime.Now,
                TimeOutInSeconds = timeout,
                ProcessThread = new Thread(new ThreadStart(delegate
                  {
                      // do task here...
                  })),
            });

            runningProcesses[runningProcesses.Count - 1].ProcessThread.Start();
        }
    }

    class RunningProcess
    {
        public int TimeOutInSeconds { get; set; }

        public DateTime StartTime { get; set; }

        public Thread ProcessThread { get; set; }
    }
}
于 2008-11-28T11:47:41.733 に答える
3

それは、停止時間をどれだけ正確にしたいかによって異なります。バッチ内のタスクがかなり高速で、あまり正確である必要がない場合は、シングル スレッドにしようとします。

DateTime runUntil = DataTime.Now.Add(timeout);
forech(Task task in tasks)
{
   if(DateTime.Now >= runUntil)
   {
        throw new MyException("Timeout");
   }
   Process(task);
}

それ以外の場合は、副作用を引き起こさずに途中でタスクを終了する方法を理解する必要があるため、常により困難なマルチスレッド化する必要があります。System.Timers のタイマーを使用できます: http://msdn.microsoft.com/en-us/library/system.timers.timer(VS.71).aspxまたは Thread.Sleep。タイムアウト イベントが発生すると、実際の処理を行うスレッドを終了し、プロセスをクリーンアップして終了できます。

于 2008-10-09T08:55:06.683 に答える
2

「タイムアウトが発生するまで」とは、「1時間処理を続けてから停止する」という意味ですか? もしそうなら、私はおそらくそれを非常に明示的にするでしょう - あなたが終了したいときに最初に働き、次にあなたの処理ループで、あなたがその時間に達したかどうかをチェックしてください. 信じられないほどシンプルで、テストが簡単です。テスト容易性の観点から、プログラムで時間を設定できる偽の時計が必要になる場合があります。

編集:明確にするための疑似コードを次に示します。

List<DataSource> dataSources = ConnectToDataSources();
TimeSpan timeout = GetTimeoutFromConfiguration(); // Or have it passed in!
DateTime endTime = DateTime.UtcNow + timeout;

bool finished = false;
while (DateTime.UtcNow < endTime && !finished)
{
    // This method should do a small amount of work and then return
    // whether or not it's finished everything
    finished = ProcessDataSources(dataSources);
}

// Done - return up the stack and the console app will close.

それは、モックできるクロックインターフェイスなどではなく、組み込みのクロックを使用しているだけですが、おそらく一般的な適切なものを理解しやすくします。

于 2008-10-09T08:43:45.507 に答える