c# 控制台程序怎么实现每天指定时刻定时

本文介绍了四种在C#中实现每日指定时间定时任务的方法,包括轮询制度、Windows计划任务或服务、轮询改进方案以及使用第三方库CronNET。文章详细讨论了每种方法的优缺点,如轮询消耗资源、计划任务管理复杂以及CronNET的使用陷阱。最后提出了结合CronNET和传统timer来实现秒级精度的解决方案。

我通常用的timer都是每隔一段时间去执行,如果想指定时刻定时怎么办?
又或者我想每天3点,5点执行任务,每周1到周5执行任务,周六周日休息,又怎么办?
查询了一些资料,大约有4类方法:

1. 轮询制度

思路是仍然设定timer,比如1分钟,每次启动定时任务后,再去判断有没有到指定时间。

    static void Main(string[] args)
    {
        System.Timers.Timer timer = new System.Timers.Timer();
        timer.Enabled = true;
        timer.Interval = 60000; //执行间隔时间,单位为毫秒; 这里实际间隔为1分钟  
        timer.Start();
        timer.Elapsed += new System.Timers.ElapsedEventHandler(test); 
//Console.Readkey()保持Console窗口不关闭,否则,该程序执行后一闪就关闭,不会等1分钟的时间。
        Console.ReadKey();
    }

   private static void test(object source, ElapsedEventArgs e)
    {
//指定的每天10:30分执行事件。这里需要注意的是,由于是指定到特定分钟执行事件
//因此,timer.Inverval的时间间隔最长不得超过1分钟,否则,长于1分钟的时间间隔有可能会错过10:30分这个时间节点,从而导致无法触发该事件
        if (DateTime.Now.Hour == 10 && DateTime.Now.Minute == 30)  //如果当前时间是10点30分
            Console.WriteLine("OK, event fired at: " + DateTime.Now.ToString());
        
    }

轮询制度是最简单的方式,缺点稍微消耗资源,不够智能。

2. window系统的计划任务或服务

这种方式把定时任务从代码中解放出来,而是托管给计划任务。
好处是可以随意设定,无需修改代码。
缺点是,这种程序自己用还行,如果分发给用户,难道还要每个用户都去设定一次计划任务?
一旦多个计划任务同时进行,还需要花费额外的精力去管理计划。
用户体验太差了。
从用户体验角度来说,最好定时任务能内嵌在程序内,用户只需要直接双击运行即可,其他无需操心。

3. 对第一种轮询的改进

//设定定时执行
setTaskAtFixedTime();
 
 
private void setTaskAtFixedTime()
{
      DateTime now = DateTime.Now;
      DateTime oneOClock = DateTime.Today.AddHours(1.0); //凌晨1:00
      if (now > oneOClock)
      {
          oneOClock = oneOClock.AddDays(1.0);
      }
      int msUntilFour = (int)((oneOClock - now).TotalMilliseconds);
 
      var t = new System.Threading.Timer(doAt1AM);
      t.Change(msUntilFour, Timeout.Infinite);
}
 
//要执行的任务
private void doAt1AM(object state)
{
     //执行功能...
 
     //再次设定
     setTaskAtFixedTime();
}

4. 直接使用第三方编写好的库

这种库不少,比如CronNET,它一个简单的C#库,基于cron调度运行任务。
cron调度最初来源于linux系统,5个*号分别代表—分钟到月—,相当灵活强大。
在这里插入图片描述
在这里插入图片描述

using System.Threading;
using CronNET;

namespace CronNETExample.Console
{
    class Program
    {
        private static readonly CronDaemon cron_daemon = new CronDaemon();            

        static void Main(string[] args)
        {
            cron_daemon.add_job(new CronJob("* * * * *", task));
            cron_daemon.start();

            // Wait and sleep forever. Let the cron daemon run.
            while(true) Thread.Sleep(6000);
        }

        static void task()
        {
          Console.WriteLine("Hello, world.")
        }
    }
}

这里有两个坑,如果是在nuget里下载,会发现以上代码无法通过编译,因为作者不一样。

在这里插入图片描述
在这里插入图片描述
nuget上的作者是josh mackey,我反复查找也没找到这个包的使用方法。
既没有github,微软nuget官网也没有。
懒得去研究这种三无产品,尽管它的下载量不低,用的人也不少。

以上代码的作者是kevincolyar,项目在github上。
在这里插入图片描述
可惜这位仁兄不发nuget,以至于2015年的时候有用户吐槽:
请发到nuget上啊!!!!
在这里插入图片描述
热心人士3年后回复:把源码拷贝进自己的项目。
果然硬核,哈哈。

第二个坑在于我下载了源码,并且编译成了dll,仍然发现代码不能正常编译。
查询发现作者修改了类的方法,以前是典型的linux命名法。
现在改成了NET命名法,也没有在示范里说明(2013年估计作者已经不维护了)。

需要修改这两处:

cron_daemon.AddJob("* * * * *", run);
cron_daemon.Start();

完美搞定,正常运行!
这种方法最大的缺点在于,精确控制是分钟级别,如果想控制到秒级别,可以用它和传统的timer配合。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值