C# 在Windows服务内的计划中运行方法

C# 在Windows服务内的计划中运行方法,c#,.net,timer,C#,.net,Timer,我有一个Windows服务,我需要在特定的时间表中运行一个方法。到目前为止,我实现了一个表示计划的类 public class SchaduleTime { public int Hour { get; set; } public int Minute { get; set; } public DateTime Next { get { var now = DateTime.Now;

我有一个Windows服务,我需要在特定的时间表中运行一个方法。到目前为止,我实现了一个表示计划的类

public class SchaduleTime
{
    public int Hour { get; set; }

    public int Minute { get; set; }

    public DateTime Next
    {
        get
        {
            var now = DateTime.Now;
            var dt = now.Date;

            // the time has passed to execute today?
            if (Hour * 60 + Minute < now.Hour * 60 + now.Minute)
            {
                dt = dt.AddDays(1);
            }

            return new DateTime(dt.Year, dt.Month, dt.Day, Hour, Minute, 0);
        }
    }
}
并在计时器字段的已用事件中运行类似的操作:

private void TimerElapsed(object sender, System.Timers.ElapsedEventArgs e)
{
    // do my work.

    // programing next:
    var nowTicks = DateTime.Now.Ticks;

    // get the next schadule.
    var next = schadules
        .Select(s => new
            {
                Schadule = s,
                IntervalNeeded = s.Next.Ticks - nowTicks
            })
        .OrderBy(o => o.IntervalNeeded)
        .First();

    timer.Enabled = false;
    timer.Stop();

    timer.Interval = (int) new TimeSpan(next.IntervalNeeded).TotalMilliseconds;

    timer.Enabled = true;
    timer.Start();
}
对我来说,这似乎是一个笨拙的策略或意大利面代码,我的意思是看起来很丑陋


有没有一种方法可以使用一个专门的类来完成这项工作,该类可以与调度或类似.net中的Windows任务调度程序一起工作,或者我的方法很好,我很吃惊?

在我看来,你的方法很好。事实上,这是一种启发。我不会想出一个计时器,然后永久地重新安排它


我会做的是——这是严格可选的,就像我说的,你的方法很好——让计时器每分钟启动一次,然后检查是否有事情要做。对于更小的时间分辨率,几秒甚至几毫秒,我不会这么做。但是让你的计时器每分钟运行一次,仅仅检查内存中的数组,然后在95%的情况下直接回到睡眠状态,这并不是一种严重的资源浪费。另外,它将允许更直接和更容易维护的代码。

让我们假设假设的情况,你有14:00的10个时间表。假设您的计时器在13:59:59停止,发生的是:

  • 10个时间表声称他们还有1秒钟的时间
  • 已用处理程序首先拾取并以1秒的间隔重新启动自身
  • 它将在14:00再次停止-此时所有计划都已返回第二天的
    Next
结果,你的10份工作中就有1份被解雇了。看起来不太好

当然,您可以选择列表,或者限制在给定的小时内只能设置一个作业。但话说回来,你还需要做出哪些其他假设?调度数组可以为空吗?当有一百万个时间表时,它能工作吗?你有这个代码的测试吗?等等

相反,您可以使用专门的库来实现这一点-。它是一个简单的作业调度程序,可以完成您在此处尝试实现的任务:

ISchedulerFactory factory= new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
scheduler.Start();

// You'll have to implement class performing actual work to be done - ServiceJob
JobDetail jobDetail = new JobDetail("ServiceJob", null, typeof(ServiceJob));
Trigger trigger = TriggerUtils.MakeDailyTrigger();
// Start time could be anytime today
trigger.StartTimeUtc = DateTime.UtcNow;
trigger.Name = "ServiceTrigger";
scheduler.ScheduleJob(jobDetail, trigger);
Quartz负责所有计时器,在请求的时间运行指定的作业,等等。它很简单,有一套很好的解决方案,你不需要实现任何东西

ISchedulerFactory factory= new StdSchedulerFactory();
IScheduler scheduler = factory.GetScheduler();
scheduler.Start();

// You'll have to implement class performing actual work to be done - ServiceJob
JobDetail jobDetail = new JobDetail("ServiceJob", null, typeof(ServiceJob));
Trigger trigger = TriggerUtils.MakeDailyTrigger();
// Start time could be anytime today
trigger.StartTimeUtc = DateTime.UtcNow;
trigger.Name = "ServiceTrigger";
scheduler.ScheduleJob(jobDetail, trigger);