Windows 服务,用于在指定时间运行函数

本文关键字:定时间 运行 函数 服务 用于 Windows | 更新日期: 2023-09-27 18:33:36

我想启动一个Windows服务,每天在特定时间运行一个函数。

我应该考虑什么方法来实现这一点?定时器还是使用线程?

Windows 服务,用于在指定时间运行函数

(1) 首次启动时,设置_timer。服务启动和计划时间之间的毫秒数的间隔。此示例将计划时间设置为 7:00 a.m.,因为 _scheduleTime = DateTime.Today.AddDays(1)。添加时间(7);

(2) Timer_Elapsed,重置_timer。如果当前间隔不是 24 小时,则间隔为 24 小时(以毫秒为单位)。

System.Timers.Timer _timer;
DateTime _scheduleTime; 
public WinService()
{
    InitializeComponent();
    _timer = new System.Timers.Timer();
    _scheduleTime = DateTime.Today.AddDays(1).AddHours(7); // Schedule to run once a day at 7:00 a.m.
}
protected override void OnStart(string[] args)
{           
    // For first time, set amount of seconds between current time and schedule time
    _timer.Enabled = true;
    _timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;                                          
    _timer.Elapsed += new System.Timers.ElapsedEventHandler(Timer_Elapsed);
}
protected void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // 1. Process Schedule Task
    // ----------------------------------
    // Add code to Process your task here
    // ----------------------------------

    // 2. If tick for the first time, reset next run to every 24 hours
    if (_timer.Interval != 24 * 60 * 60 * 1000)
    {
        _timer.Interval = 24 * 60 * 60 * 1000;
    }  
}

编辑:

有时人们希望将服务安排在第 0 天开始,而不是明天,因此他们更改DateTime.Today.AddDays(0)。如果他们这样做并设置过去的时间,则会导致使用负数设置间隔时出错。

//Test if its a time in the past and protect setting _timer.Interval with a negative number which causes an error.
double tillNextInterval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;
if (tillNextInterval < 0) tillNextInterval += new TimeSpan(24, 0, 0).TotalSeconds * 1000;
_timer.Interval = tillNextInterval;

您确定需要每天只运行一次的服务吗?

也许Windows任务计划将是更好的解决方案?

很好的答案(我使用了你的代码),但是这一行有一个问题:

_timer.Interval = _scheduleTime.Subtract(DateTime.Now).TotalSeconds * 1000;

如果 DateTime.now 晚于 scheduleTime,您将变为负数,这将在分配给计时器时生成异常。间隔。

我使用过:

if (DateTime.now > scheduleTime)
    scheduleTime = scheduleTime.AddHours(24);

然后做减法。

使用任务计划程序 (http://windows.microsoft.com/en-us/windows7/schedule-a-task) 或 Quartz.net 中内置的 Windows。

除非。。。您有一个正在执行许多其他处理的服务,并且需要一直运行,在这种情况下,计时器可能是合适的。

private static double scheduledHour = 10;
private static DateTime scheduledTime;
public WinService()
{
     scheduledTime = DateTime.Today.AddHours(scheduledHour);//setting 10 am of today as scheduled time- service start date
}
private void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
      DateTime now = DateTime.Now;
      if (scheduledTime < DateTime.Now)
      {
         TimeSpan span = now - DateTime.Now;
         scheduledTime = scheduledTime.AddMilliseconds(span.Milliseconds).AddDays(1);// this will set scheduled time to 10 am of next day while correcting the milliseconds
         //do the scheduled task here
      }  
}

您可以使用线程和事件来执行此操作; 计时器不是必需的。

using System;
using System.ServiceProcess;
using System.Threading;
partial class Service : ServiceBase
{
    Thread Thread;
    readonly AutoResetEvent StopEvent;
    public Service()
    {
        InitializeComponent();
        StopEvent = new AutoResetEvent(initialState: false);
    }
    protected override void Dispose(bool disposing)
    {
        if (disposing)
        {
            StopEvent.Dispose();
            components?.Dispose();
        }
        base.Dispose(disposing);
    }
    protected override void OnStart(string[] args)
    {
        Thread = new Thread(ThreadStart);
        Thread.Start(TimeSpan.Parse(args[0]));
    }
    protected override void OnStop()
    {
        if (!StopEvent.Set())
            Environment.FailFast("failed setting stop event");
        Thread.Join();
    }
    void ThreadStart(object parameter)
    {
        while (!StopEvent.WaitOne(Timeout(timeOfDay: (TimeSpan)parameter)))
        {
            // do work here...
        }
    }
    static TimeSpan Timeout(TimeSpan timeOfDay)
    {
        var timeout = timeOfDay - DateTime.Now.TimeOfDay;
        if (timeout < TimeSpan.Zero)
            timeout += TimeSpan.FromDays(1);
        return timeout;
    }
}

如果是一天一个,为什么不使用任务计划程序?当您希望在几分钟内多次运行任务时,Windows 服务很有用。因此,如果要在特定时间运行程序,最好使用任务计划程序并在一天中的特定时间设置任务计划程序的事件。我用任务计划程序做了很多事情,它很完美。您可以在任务计划程序中设置程序的路由并设置运行它的间隔时间。如果您想在一天内每 5 分钟运行一次程序,您仍然可以使用任务计划程序及其更好的方法。