【问题标题】:Windows Service to run a function at specified timeWindows 服务在指定时间运行功能
【发布时间】:2013-10-03 05:21:49
【问题描述】:

我想启动一个 Windows 服务来每天在特定时间运行一个功能。

我应该考虑用什么方法来实现它?计时器还是使用线程?

【问题讨论】:

    标签: c# timer windows-services


    【解决方案1】:

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

    (2) 在 Timer_Elapsed 上,如果当前间隔不是 24 小时,则将 _timer.Interval 重置为 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 任务计划程序运行它
    • 我想如果任务执行时间长的话,下次就不会正好在7点运行了。它会继续增长。
    • 每天以7:00 a.m to 21:00 pm 的间隔运行周一至周五 ? 非东部节日
    【解决方案2】:

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

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

    如果 DateTime.now 晚于 scheduleTime,您将否定,这将在分配给 timer.Interval 时产生异常。

    我用过:

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

    然后做减法。

    【讨论】:

    • 在这种情况下你应该这样做 while (DateTime.now > scheduleTime) { scheduleTime = scheduleTime.AddHours(24);如果超过 1 天,它只会让它变得更好......它解决了可能发生的任何奇怪问题
    【解决方案3】:

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

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

    【讨论】:

      【解决方案4】:

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

      除非......您有一个服务正在执行大量其他处理并且需要一直运行,在这种情况下,Timer 可能是合适的。

      【讨论】:

      • 任何使用Quartz.net的完整样本? Windows 服务中的应用程序域?控制台应用程序?
      【解决方案5】:
      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
            }  
      }
      

      【讨论】:

        【解决方案6】:

        你可以用一个线程和一个事件来做到这一点;不需要计时器。

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

        【讨论】:

          【解决方案7】:

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

          【讨论】:

            猜你喜欢
            • 2012-09-27
            • 1970-01-01
            • 2014-02-03
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-01-23
            • 1970-01-01
            相关资源
            最近更新 更多