.Net之时间轮算法(终极版)定时任务
TimeWheelDemo
一个基于时间轮原理的定时任务
对时间轮的理解
其实我是有一篇文章(.Net 之时间轮算法(终极版)[1])针对时间轮的理论理解的,但是,我想,为啥我看完时间轮原理后,会采用这样的方式去实现。
可能只是一些小技巧不上大雅之堂吧,大佬看看就行了。
当然如果大佬有别的看法,也请不吝赐教,互相交流,一起进步。
项目是基于时间轮理解上的一个任务调度轻型框架
作用么,造个小轮子,顺便,对任务调度的实现多一些深度的思考和了解。
这个框架实现了啥子
实现了对方法的定时 循环执行。大概样子是下面这样的
TimeWheel timeWheel = new TimeWheel();timeWheel.AddTask(new Job("定时1", () => { Console.WriteLine($"定时每1秒 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(1))));timeWheel.AddTask(new Job("定时2", () => { Console.WriteLine($"定时2每10执行 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(10))));timeWheel.AddTask(new Job("CRON", () => { Console.WriteLine($"CRON 每5秒 {DateTime.Now}"); }, new CronTask("*/5 * * * * *")));timeWheel.AddTask(new Job("死信", () => { Console.WriteLine($"死信执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(20))));timeWheel.AddTask(new Job("死信1", () => { Console.WriteLine($"死信1执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(10))));timeWheel.Run();
能实现,定时任务,死信任务,能支持CRON表达式
定时任务如下 (TimeTask)
timeWheel.AddTask(new Job("定时1", () => { Console.WriteLine($"定时每1秒 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(1))));timeWheel.AddTask(new Job("定时2", () => { Console.WriteLine($"定时2每10执行 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(10))));
通过 TimeTask进行实现的
CRON定时任务 (CronTask)
主要是基于 NCrontab 库,实现对CRON表达式的解析。省的自己从头解析了
timeWheel.AddTask(new Job("CRON", () => { Console.WriteLine($"CRON 每5秒 {DateTime.Now}"); }, new CronTask("*/5 * * * * *")));
这样就能实现对特定任务的执行
死信任务,延迟任务 (DelayTask)
很多死信都是基于消息队列的,但是应该也有一些实际应用中的应用场景吧。看具体了。
timeWheel.AddTask(new Job("死信", () => { Console.WriteLine($"死信执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(20))));timeWheel.AddTask(new Job("死信1", () => { Console.WriteLine($"死信1执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(10))));
实现
能按照指定ID名,来实现对任务的移除
比如下边的,就能直接移除死信的任务。可以别的定时器执行了任务,然后,对此任务进行清除。
timeWheel.RemoveTask("死信");
基本上,只要没有被执行的任务,都会被取消执行的。
效果图
代码详解
先看看main函数的示例
static void Main(string[] args)
{TimeWheel timeWheel = new TimeWheel();timeWheel.AddTask(new Job("定时1", () => { Console.WriteLine($"定时每1秒 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(1))));timeWheel.AddTask(new Job("定时2", () => { Console.WriteLine($"定时2每10执行 {DateTime.Now}"); }, new TimeTask(TimeSpan.FromSeconds(10))));timeWheel.AddTask(new Job("CRON", () => { Console.WriteLine($"CRON 每5秒 {DateTime.Now}"); }, new CronTask("*/5 * * * * *")));timeWheel.AddTask(new Job("死信", () => { Console.WriteLine($"死信执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(20))));timeWheel.AddTask(new Job("死信1", () => { Console.WriteLine($"死信1执行 {DateTime.Now}"); }, new DelayTask(TimeSpan.FromSeconds(10))));timeWheel.Run();Task.Run(() =>{Thread.Sleep(10 * 1000);timeWheel.RemoveTask("死信");Console.WriteLine("移除死信");Thread.Sleep(10 * 1000);timeWheel.RemoveTask("CRON");Console.WriteLine("移除任务CRON");});Console.WriteLine("开始运行时间轮!");Console.ReadLine();
}
时间调度
/// <summary>/// 时间调度方式/// </summary>public interface IScheduledTask{/// <summary>/// 获取下一个时间/// </summary>/// <returns></returns>public DateTime? GetNextTime();}
核心的时间轮
/// <summary>/// 时间轮算法(终极)实现/// 大部分都是支持秒级,所以,按照秒级进行实现/// 任务体得有它自己的任务唯一的ID/// </summary>public class TimeWheel{/// <summary>/// 时间调度列表/// </summary>private ConcurrentDictionary<long, HashSet<string>> TimeTasks { get; set; } = new();/// <summary>/// 任务列表/// </summary>private ConcurrentDictionary<string, IJob> ScheduledTasks { get; set; } = new();/// <summary>/// 是否运行中/// </summary>private bool isRuning = false;/// <summary>/// 运行核心/// </summary>public void Run(){isRuning = true;Task.Run(() =>{while (isRuning){var timeStamp = GenerateTimestamp(DateTime.Now);Task.Run(() => { Trigger(timeStamp); });var offset = 500 - DateTime.Now.Millisecond;SpinWait.SpinUntil(() => false, 1000 + offset);}});}public void Stop(){isRuning = false;}/// <summary>/// 定时触发器/// </summary>/// <param name="timeStamp"></param>private void Trigger(long timeStamp){var oldTimeStamp = timeStamp - 1;var list = TimeTasks.Keys.Where(t => t <= oldTimeStamp).ToList();foreach (var item in list){TimeTasks.TryRemove(item, out var _);}TimeTasks.TryGetValue(timeStamp, out var result);if (result?.Any() == true){var Now = DateTime.Now;foreach (var id in result){//找到指定的任务if (ScheduledTasks.TryGetValue(id, out IJob job)){Task.Run(() => { job.Execute(); });var NewTime = job.GetNextTime();if (NewTime.HasValue && NewTime >= Now){AddTask(NewTime.Value, id);}}}}}/// <summary>/// 添加任务/// </summary>/// <param name="dateTime"></param>/// <param name="scheduledTask"></param>private void AddTask(DateTime dateTime, string ID){var timeStamp = GenerateTimestamp(dateTime);TimeTasks.AddOrUpdate(timeStamp, new HashSet<string>() { ID }, (k, v) =>{v.Add(ID);return v;});}/// <summary>/// 增加一个任务/// </summary>public void AddTask(IJob job){if (ScheduledTasks.ContainsKey(job.ID)){throw new ArgumentException($"{nameof(job)} 参数 {nameof(job.ID)}重复!");}else{ScheduledTasks.TryAdd(job.ID, job);}var time = DateTime.Now;var NewTime = job.GetNextTime();if (NewTime.HasValue && NewTime >= time){Console.WriteLine($"新增任务:{job.ID}");AddTask(NewTime.Value, job.ID);}}/// <summary>/// 移除某个任务的Task/// </summary>/// <param name="ID"></param>public void RemoveTask(string ID){var ids = ScheduledTasks.Values.Where(t => t.ID == ID)?.Select(t => t.ID).ToList();if (ids?.Any() == true){foreach (var id in ids){if (ScheduledTasks.TryGetValue(id, out var job)){job.Cancel();ScheduledTasks.TryRemove(id, out _);}}}}/// <summary>/// 获取时间戳/// </summary>private long GenerateTimestamp(DateTime dateTime){return new DateTimeOffset(dateTime.ToUniversalTime()).ToUnixTimeSeconds();}}
任务体 (IJob)
/// <summary>/// 任务体/// </summary>public interface IJob{/// <summary>/// 任务ID,唯一/// </summary>/// <returns></returns>public string ID { get; }/// <summary>/// 脚本/// </summary>/// <returns></returns>public void Execute();/// <summary>/// 取消执行/// </summary>public void Cancel();/// <summary>/// 获取任务执行时间/// </summary>/// <returns></returns>public DateTime? GetNextTime();}
框架特点是啥
只有一个字,轻。用的舒服点。有问题大家一起沟通
框架地址
https://github.com/kesshei/TimeWheelDemo
引用链接
[1]
.Net 之时间轮算法(终极版): #https://blog.csdn.net/i2blue/article/details/123608471
.Net之时间轮算法(终极版)定时任务相关推荐
- 【定时任务】时间轮算法
目录 1 从定时任务说起 2 初识时间轮 3 绝对时间和相对时间 4 需要重复执行多次的任务 5 同一时刻存在多个任务 6 时间轮的数据结构 7 时间刻度不够用怎么办? 7.1 增大时间轮的刻度 7. ...
- 从 Kafka 看时间轮算法设计
欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://juejin.cn/post/7047405443961847816 前言 Kafka 中有很多延时操作,比如 ...
- java 时间轮算法_时间轮算法(TimingWheel)是如何实现的?
前言 我在2. SOFAJRaft源码分析-JRaft的定时任务调度器是怎么做的?这篇文章里已经讲解过时间轮算法在JRaft中是怎么应用的,但是我感觉我并没有讲解清楚这个东西,导致看了这篇文章依然和没 ...
- 原 荐 简单说说Kafka中的时间轮算法
零.时间轮定义简单说说时间轮吧,它是一个高效的延时队列,或者说定时器.实际上现在网上对于时间轮算法的解释很多,定义也很全,这里引用一下 朱小厮博客 里出现的定义:参考下图,Kafka中的时间轮(Tim ...
- 时间轮算法解析(Netty HashedWheelTimer源码解读)
1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...
- 心跳超时时间设置_定时器实现之时间轮算法
前言 在看这篇文章的时候对其中超时控制一块儿有点好奇.通过时间轮来控制超时?啥是时间轮?怎么控制的?文章会先介绍常见的计时超时处理,再引入时间轮介绍及 netty 在实现时的一些细节,最后总结下实现的 ...
- java 时间轮算法_时间轮算法解析(Netty HashedWheelTimer源码解读)
1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...
- TimeWheel时间轮算法原理及实现(附源码)
时间轮算法原理及实现 前言 1.时间轮核心 2.简单定时器 3.任务队列 4.优化任务队列 5.简单时间轮 6.多层时间轮 前言 在各种业务场景中,我们总是会需要一些定时进行一些操作,这些操作可能是 ...
- 时间轮算法(TimingWheel)
时间轮算法的应用非常广泛,在 Dubbo.Netty.Kafka.ZooKeeper.Quartz 的组件中都有时间轮思想的应用,甚至在 Linux 内核中都有用到. 其思想理论基础可以参考论文:ht ...
最新文章
- 2022-2028年中国钢筘行业市场研究及前瞻分析报告
- 20145129 《Java程序设计》第6周学习总结
- ML之LiR之PLiR:惩罚线性回归PLiR算法简介、分类、代码实现之详细攻略
- Xen和虚拟化技术学习指南
- android开发 RecyclerView 瀑布列表布局
- C#~异步编程续~.net4.5主推的awaitasync应用
- STL源码剖析 算法章节 算法总览
- git subtree 管理项目子模块
- Linux学习笔记 --网络配置及进程管理
- 【转】如何查看linux版本 如何查看LINUX是多少位
- CSDN CODE 将于本月底彻底关闭,请尽快迁移到码云
- 工信部定级备案和等保备案有什么区别
- PL/SQL Oracle恢复默认界面设置
- 如何快速将jpg格式文件转换成bmp格式
- LTE CQI优化提升方法
- Github 学习 (整理自http://stormzhang.com/github/2016/06/04/learn-github-from-zero4/ 张哥学Git)
- 如何理解实践标准是确定性和不确定性的统一
- H ICPC Standings
- cecs计算机科学与技术,发布12个正宗IEEE/EI会议 (6月30-7月25号投稿截止) - 学术会议 - 小木虫 - 学术 科研 互动社区...
- DTCC呼吁银行和监管机构帮助解决区块链安全问题