简体   繁体   English

C#console批处理应用程序中的最佳计时器方法

[英]Best Timer approach in C# console batch application

Which is the best timer approach for a C# console batch application that has to process as follows: 哪个是C#控制台批处理应用程序的最佳计时器方法,必须按如下方式处理:

  1. Connect to datasources 连接到数据源
  2. process batch until timeout occurs or processing complete. 处理批处理直到超时发生或处理完成。 "Do something with datasources" “用数据源做点什么”
  3. stop console app gracefully. 优雅地停止控制台应用程序

related question: How do you add a timer to a C# console application 相关问题: 如何向C#控制台应用程序添加计时器

Sorry for this being an entire console app... but here's a complete console app that will get you started. 很抱歉这是一个完整的控制台应用程序......但这里有一个完整的控制台应用程序,可以帮助您入门。 Again, I appologize for so much code, but everyone else seems to be giving a "oh, all you have to do is do it" answer :) 再一次,我为这么多代码道歉,但其他人似乎都在给“哦,你所要做的就是做到这一点”答案:)

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; }
    }
}

It depends on how accurate do you want your stopping time to be. 这取决于您希望停止时间的准确程度。 If your tasks in the batch are reasonably quick and you don't need to be very accurate, then I would try to make it single threaded: 如果批处理中的任务相当快,而且您不需要非常准确,那么我会尝试使其成为单线程:

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

Otherwise you need to go mulithreaded, which is always more difficult, because you need to figure out how to terminate your task in the middle without causing side effects. 否则你需要多线程,这总是比较困难,因为你需要弄清楚如何在中间终止任务而不会产生副作用。 You could use the Timer from System.Timers: http://msdn.microsoft.com/en-us/library/system.timers.timer(VS.71).aspx or Thread.Sleep. 您可以使用System.Timers中的Timer: http//msdn.microsoft.com/en-us/library/system.timers.timer (VS.71) .aspx或Thread.Sleep。 When the time-out event occurs you can terminate the thread that does the actual processing, clean up and end the process. 发生超时事件时,您可以终止执行实际处理的线程,清理并结束该过程。

When you say "until timeout occurs" do you mean "keep processing for an hour and then stop"? 当你说“直到发生超时”时你的意思是“继续处理一小时然后停止”? If so, I'd probably just make it very explicit - work out at the start when you want to finish, then in your processing loop, do a check for whether you've reached that time or not. 如果是这样,我可能只是非常明确地说 - 在你想要完成时从头开始工作,然后在你的处理循环中,检查你是否已经达到那个时间。 It's incredibly simple, easy to test etc. In terms of testability, you may want a fake clock which would let you programmatically set the time. 它非常简单,易于测试等。在可测试性方面,您可能需要一个可以让您以编程方式设置时间的假时钟。

EDIT: Here's some pseudocode to try to clarify: 编辑:这是一些试图澄清的伪代码:

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.

That's just using the built-in clock rather than a clock interface which can be mocked, etc - but it probably makes the general appropriate simpler to understand. 这只是使用内置时钟而不是可以模拟的时钟接口等 - 但它可能使得一般更容易理解。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM