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

时间:2020-12-26 20:35:13

Which is the best timer approach for a C# console batch application that has to process as follows:

哪个是C#控制台批处理应用程序的最佳计时器方法,必须按如下方式处理:

  1. Connect to datasources
  2. 连接到数据源

  3. process batch until timeout occurs or processing complete. "Do something with datasources"
  4. 处理批处理直到超时发生或处理完成。 “用数据源做点什么”

  5. stop console app gracefully.
  6. 优雅地停止控制台应用程序

related question: How do you add a timer to a C# console application

相关问题:如何向C#控制台应用程序添加计时器

3 个解决方案

#1


4  

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

#2


3  

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. When the time-out event occurs you can terminate the thread that does the actual processing, clean up and end the process.

否则你需要多线程,这总是比较困难,因为你需要弄清楚如何在中间终止任务而不会产生副作用。您可以使用System.Timers中的Timer:http://msdn.microsoft.com/en-us/library/system.timers.timer(VS.71).aspx或Thread.Sleep。发生超时事件时,您可以终止执行实际处理的线程,清理并结束该过程。

#3


2  

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.

这只是使用内置时钟而不是可以模拟的时钟接口等 - 但它可能使得一般适当的更容易理解。

#1


4  

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

#2


3  

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. When the time-out event occurs you can terminate the thread that does the actual processing, clean up and end the process.

否则你需要多线程,这总是比较困难,因为你需要弄清楚如何在中间终止任务而不会产生副作用。您可以使用System.Timers中的Timer:http://msdn.microsoft.com/en-us/library/system.timers.timer(VS.71).aspx或Thread.Sleep。发生超时事件时,您可以终止执行实际处理的线程,清理并结束该过程。

#3


2  

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.

这只是使用内置时钟而不是可以模拟的时钟接口等 - 但它可能使得一般适当的更容易理解。