定时任务的处理
对于定时任务,一般由时间戳Timers 或者死循环While(true) 操作,两者都能达到,指定间隔时间内执行去执行任务,这里不做效率的比较,只说明一下适合的场景。先拿while来说,执行完成任务后,设置好线程等待时间即可,它有一优势,即如果此次任务未执行完,则不会进入下一次,也就是说是可控的,不会同时执行两笔相同任务
public void StartLoadTask() { while (true) { //... 业务逻辑//等待60秒,进入下一次 Thread.Sleep(60000); } }
再来看一看Times ,这里仅作 System.Timers 下的timer的说明(非 Threading 中的timer),如下图
//执行定时服务 var timer = new Timer() { AutoReset = true, Enabled = true, Interval=60000 }; timer.Elapsed += (sender, eventArgs) => Helper.StartTask();
可以满足每隔60s 调用一次 StartTask 方法,但是会有一个问题,试想如果由于某个内部或外部原因,导致执行一次程序的时间超过了60s,如果直接这样写,则会出现第一个任务还未执行完,下一个任务又进来,则同时运行两笔任务的情况,显然是不可取的,需要进行改进,即需等上次任务执行完,再去等待间隔,然后进入下一次任务,否则永远要等上一笔任务执行完。这里将 timer 当做参数 传递给 StartTask 方法,则
public void StartTask(Timer timer) { timer.Stop(); //... 业务逻辑 timer.Start(); }
看似两种操作都达到了需求,细想下来,还有不妥。试想任务是每分钟执行一次的,虽然这样处理解决了不会同时执行多笔任务的问题,可若任务执行时间超过了60s,则错过了下一次任务的执行时间。这样的话岂不是顾此失彼,既要每次只执行一笔任务,又不能错过每一次任务。想要满足这种要求,则只能引用安全队列机制,每隔60s,便把任务写入队列中,再启一个线程去循环读取队列里的任务便可。这样一个线程尽管往里面写,另外一个线程负责取,每执行完一笔任务,就去读下一笔任务,如此往复。
写入队列如下
public void StartTask() { //任务t //写入任务队列 TaskQueue.Enqueue(t); LogHelper.LogQueue.Enqueue("写入报告任务:" + t.Date); }
取出队列如下
public void StartTask() { while (true) { if (!TaskQueue.IsEmpty) { //取出任务 TaskQueue.TryDequeue(out ICCTask task); LogHelper.LogQueue.Enqueue("取出报告任务:" + task.Date); //执行任务 逻辑 // ... } Thread.Sleep(60000); } }
当然取出队列任务 需要设置线程为 异步 Task.Factory.StartNew(StartTask);
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构