你如何创建一个以延迟开始并在c#中使用秒表的计时器

时间:2016-04-26 04:30:12

标签: c# timer timespan stopwatch

我在创建计时器时遇到问题,启动时首先会睡2分钟。它总共运行5分钟,每分钟都可以运行。这就是我所拥有的:

class Program{
    static System.Timers.Timer aTimer;
    static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    static TimeSpan LongToRun = new TimeSpan(0,300,0)); //run for 5 minutes

    static void Main (string[] args){
        Thread.Sleep(120000); //sleep for 2 mins
        sw.Reset();
        sw.Start();
        Start();
    }

    static void Start()
    {
        aTimer = new System.Timers.Timer();
        aTimer.Interval = 60000;  //every min
        aTimer.Enabled = true;
        aTimer.Elapsed += new ElapsedEventHandler(timer_Elapsed); 
        aTimer.Start();

    }

    static void timer_Elapsed(object sender, ElapsedEventArgs e)
    {
        TimeSpan ts = sw.Elapsed;
        if (ts.TotalSeconds >= LongToRun.TotalSeconds)
        {
            aTimer.Stop();
            return;
        }

        DoWork();
    }
}   

timer_Elapsed永远不会被调用......我是否会这样做?

提前致谢!!

3 个答案:

答案 0 :(得分:1)

启动过程在启动计时器后立即返回并返回主程序。主程序结束,仍在运行的计时器在结束之前完成。

解决方案:确保您的程序运行时间足以让计时器过去。

  • 主程序在启动计时器
  • 之前创建一个System.Threading.ManualResetEvent
  • 启动计时器后,它等待使用ManualResetEvent.WaitOne()
  • 设置ManualResetEvent
  • 在timer_elapsed函数结束时,该函数使用ManualResetEvent.Set
  • 引发事件
  • 主程序中等待此事件的线程继续处理。

另一个问题是您在启动计时器后订阅了该事件。这可能不是问题的原因,但在启动计时器之前,整齐的代码将是订阅。

顺便说一下,timer类实现了IDisposable。这意味着该类的设计者通知您他使用了需要尽快释放的稀缺资源。考虑在不再需要时立即处理Timer类。 using(...)语句是理想的。

使用async-await可以使您的代码更易于阅读和维护。

请考虑以下代码:

public static void Main()
{
    Thread.Sleep(TimeSpan.FromMinutes(2));
    var myTask = Task.Run( () => WorkerTask())
    Task.Wait(myTask);
}

private static TimeSpan longToRun = new TimeSpan.FromMinutes(5);
// easier to read than new TimeSpan(0,300,0));

public static async Task WorkerTask()
{
    StopTime = DateTime.Now + longToRun;

    // repeatedly wait a while and DoWork():
    while (DateTime.Now < StopTime)
    {
        await Task.Delay(TimeSpan.FromMinutes(2);
        DoWork();
    }
}

全部,不需要ManualResetEents,没有Stopwatches,没有Timers也没有timer_elapsed事件处理程序。

将参数传递给过程WorkerTask()甚至取消事件也很容易,因为操作员按下&lt; esc&gt;如果您创建CancellationTokenSource并将CancellationToken作为参数传递给WorkerTask,则很容易。事实上,这会使代码更简单:

public static void Main()
{
    Thread.Sleep(TimeSpan.FromMinutes(2));
    using (var tokenSource = new CancellationTokenSource())
    {
        var myTask = Task.Run( () => WorkerTask(tokenSource.Token))
        tokenSource.CancelAfter(TimerSpan.FromMinutes(5));
        // instead of LongToRun
        Task.Wait(myTask);
    }
}

public static async Task WorkerTask(CancellationToken token)
{
    // repeatedly wait a while and DoWork():
    while (!token.IsCancellationRequested)
    {
        await Task.Delay(TimeSpan.FromMinutes(2, token);
        DoWork();
    }
}

更多信息:

答案 1 :(得分:0)

首先,您设置了错误的时间段:

<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">

从不调用timer_Elapsed,因为您的应用程序先前已关闭。最后添加Console.ReadLine()。

static TimeSpan LongToRun = new TimeSpan(0,**5**,0)); //run for 5 minutes

答案 2 :(得分:0)

正如谢尔盖所​​指出的那样,在Timespan LongToRun中设置的时间段内存在错误。我尝试过一个只有Thread.sleep函数的鳕鱼。希望代码对您有所帮助。

class Program {
    static System.Timers.Timer aTimer;
    static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
    static TimeSpan LongToRun = new TimeSpan(0,5,0); //run for 5 minutes

    static void Main (string[] args)    {
        Console.WriteLine("Start Of Program" + DateTime.Now);
        Thread.Sleep(120000); //sleep for 2 mins
        sw.Reset();
        sw.Start();
        Start();
    }

    static void Start() {
        TimeSpan ts = sw.Elapsed;
        while (ts.TotalSeconds < LongToRun.TotalSeconds) {
            doWork();
            Thread.Sleep(60000);
            ts = sw.Elapsed;
        }
        Console.WriteLine("End of program");
        Console.ReadLine();
    }

    static void doWork() {
         Console.WriteLine(DateTime.Now);
    }
}