对于必须按以下方式处理的 C# 控制台批处理应用程序,这是最好的计时器方法:
- 连接到数据源
- 处理批处理,直到发生超时或处理完成。“用数据源做点什么”
- 优雅地停止控制台应用程序。
相关问题:如何将计时器添加到 C# 控制台应用程序
对于必须按以下方式处理的 C# 控制台批处理应用程序,这是最好的计时器方法:
相关问题:如何将计时器添加到 C# 控制台应用程序
抱歉,这是一个完整的控制台应用程序……但这是一个完整的控制台应用程序,可以帮助您入门。再一次,我为这么多代码道歉,但其他人似乎都在给出“哦,你所要做的就是去做”的答案:)
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; }
}
}
这取决于您希望停止时间有多准确。如果您在批处理中的任务相当快并且您不需要非常准确,那么我会尝试使其成为单线程:
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。当超时事件发生时,您可以终止执行实际处理的线程,清理并结束进程。
当您说“直到发生超时”时,您的意思是“继续处理一个小时然后停止”吗?如果是这样,我可能会说得非常明确——在你想完成的时候开始工作,然后在你的处理循环中,检查你是否已经到了那个时间。它非常简单,易于测试等。就可测试性而言,您可能需要一个假时钟,它可以让您以编程方式设置时间。
编辑:这里有一些伪代码试图澄清:
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.
那只是使用内置时钟而不是可以模拟的时钟接口等 - 但它可能使一般适当的更容易理解。