定时器每隔5分钟运行一次

我如何每隔5分钟运行一些function? 示例:我只想在14:00,14:05,14:10等时间运行sendRequest()等。

我想在C#中以编程方式进行。 该应用程序是Windows服务。

六年前发布的答案很有用。 但是,恕我直言与现代C#现在更好地使用基于Task的API与asyncawait 。 另外,我对实现的具体细节略有不同,例如如何管理延迟计算以及如何将当前时间舍入到下一个五分钟的间隔。

首先,我们假设sendRequest()方法返回void并且没有参数。 然后,我们假设基本要求是大约每五分钟运行一次(也就是说它在一小时的五分钟内完全运行并不重要)。 那么这可以很容易地实现,像这样:

 async Task RunPeriodically(Action action, TimeSpan interval, CancellationToken token) { while (true) { action(); await Task.Delay(interval, token); } } 

它可以像这样调用:

 CancellationTokenSource tokenSource = new CancellationTokenSource(); Task timerTask = RunPeriodically(sendRequest, TimeSpan.FromMinutes(5), tokenSource.Token); 

tokenSource.Cancel() ,循环将被await Task.Delay(...)语句中抛出的TaskCanceledException中断。 否则, sendRequest()方法将每五分钟调用一次(当调用RunPeriodically()方法时立即调用它…如果你想让它在第一次等待,你可以重新排序循环中的语句)。

这是最简单的版本。 相反,如果您确实希望以五分钟的间隔执行操作,则可以执行类似的操作,但计算下一个运行时间并延迟一段适当的时间。 例如:

 // private field somewhere appropriate; it would probably be best to put // this logic into a reusable class. DateTime _nextRunTime; async Task RunPeriodically(Action action, DateTime startTime, TimeSpan interval, CancellationToken token) { _nextRunTime = startTime; while (true) { TimeSpan delay = _nextRunTime - DateTime.UtcNow; if (delay > TimeSpan.Zero) { await Task.Delay(delay, token); } action(); _nextRunTime += interval; } } 

这样称呼:

 CancellationTokenSource tokenSource = new CancellationTokenSource(); DateTime startTime = RoundCurrentToNextFiveMinutes(); Task timerTask = RunPeriodically(sendRequest, startTime, TimeSpan.FromMinutes(5), tokenSource.Token); 

辅助方法RoundCurrentToNextFiveMinutes()如下所示:

 DateTime RoundCurrentToNextFiveMinutes() { DateTime now = DateTime.UtcNow, result = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0); return result.AddMinutes(((now.Minute / 5) + 1) * 5); } 

在任一示例中, timerTask对象都可用于监视循环的状态。 在大多数情况下,可能不需要它。 但是,如果您希望能够,例如await代码的其他部分取消循环,则此对象就是您要使用的对象。

请注意, Task.Delay()方法在其实现中确实使用了计时器。 上述内容不建议用于避免使用计时器,而是使用现代C# async / awaitfunction显示原始目标的实现。 此版本将与已使用async / await其他代码更清晰地进行网格await

使用System.Threading.Timer 。 您可以指定定期调用的方法。

例:

 Timer timer = new Timer(Callback, null, TimeSpan.Zero, TimeSpan.FromMinutes(5)); public void Callback(object state) { Console.WriteLine("The current time is {0}", DateTime.Now); } 

您可以使用第二个参数将状态传递给回调。

请注意,您需要以某种方式保持应用程序活动(例如,将其作为服务运行)。

至于如何确保它以hh:mm运行,其中mm % 5 == 0 ,您可以执行以下操作。

 DateTime now = DateTime.Now; int additionalMinutes = 5 - now.Minute % 5; if(additionalMinutes == 0) { additionalMinutes = 5; } var nearestOnFiveMinutes = new DateTime( now.Year, now.Month, now.Day, now.Hour, now.Minute, 0 ).AddMinutes(additionalMinutes); TimeSpan timeToStart = nearestOnFiveMinutes.Subtract(now); TimeSpan tolerance = TimeSpan.FromSeconds(1); if (timeToStart < tolerance) { timeToStart = TimeSpan.Zero; } var Timer = new Timer(callback, null, timeToStart, TimeSpan.FromMinutes(5)); 

请注意,当此代码执行时,当now非常接近最接近的hh:mmmm % 5 == 0时, tolerance是必需的。 你可以用小于一秒的值逃脱,但我会把它留给你。

使用System.Threading.Timer:

 var timer = new Timer(TimerTick, null, TimeSpan.Zero, new TimeSpan(0, 0, 0, 1)); int lastMinute = 1; void TimerTick(object state) { var minute = DateTime.Now.Minutes; if (minute != lastMinute && minute % 5 == 0) { lastMinute = minute; //do stuff } } 

这可能看起来有点笨拙和低效,因为它必须每秒调用一次,但实际上每秒执行一次检查的CPU周期数实际上几乎可以忽略不计。

(对不起,如果代码不是100%正确;我现在没有IDE。

你可以创建一个包含这样的循环的线程

 void Runner(){ while(1){ Thread t = new thread( target_method ); t.start(); sleep(5 * 60 * 1000); } } 

这有点快,又脏,但要做的工作:)

你可以先运行一个线程

  1. 检查下一个第5分钟的睡眠时间(如果它是13:59:51,它会睡9秒)
  2. 采取行动;
  3. 然后睡了5分钟
  4. 转到第2步

这个类是你需要的每一个,你只需设置委托调用和你的代表之间的时间量就可以了:)

http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx

你最好给自己一个执行方法条件的线程

 While(programStatus == ProgramStatus.Working) { While (true) { // Do your stuff } Thread.Sleep(TheTimeYouWantTheThreadToWaitTillTheNextOperation); } 

您正在寻找的是实现“cron”工作的代码。 有一些库可以做到这一点(quartz.net就是其中之一)。 我发现它们中的许多都很笨重而且有许多function。 这是我在一些项目中使用的更精简的实现:

http://blog.bobcravens.com/2009/10/an-event-based-cron-scheduled-job-in-c/

PS我的服务器现在似乎已关闭。 我正在努力。

希望有所帮助。

短发

有几种方法可以做到这一点,你可以创建一个每5分钟运行一次的计时器,当时间达到5分钟间隔之一时启动它,或者让它每隔几秒运行一次并检查时间是否可被5整除

 System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer(); // create a new timer timer.interval = 300000; //300000 = 5 minutes 

然后创建一个tick函数并添加一个事件处理程序

 timer.Tick += new EventHandler(TimerTickHandler); //add the event handler timer.Start(); //start the timer 

我同意Peter Duniho的观点 – 现代C#在这方面要好得多。

我建议使用Microsoft的Reactive Framework(NuGet“System.Reactive”)然后你可以这样做:

 IObservable timer = Observable .Defer(() => { var now = DateTimeOffset.Now; var result = new DateTimeOffset(now.Year, now.Month, now.Day, now.Hour, 0, 0, now.Offset); result = result.AddMinutes(((now.Minute / 5) + 1) * 5); return Observable.Timer(result, TimeSpan.FromMinutes(5.0)); }); timer.Subscribe(x => { /* Your code here that run on the 5 minute every 5 minutes. */ }); 

我得到了这样的结果:

 2016/08/11 14:40:00 +09:30
 2016/08/11 14:45:00 +09:30
 2016/08/11 14:50:00 +09:30