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. 【定时任务】时间轮算法

    目录 1 从定时任务说起 2 初识时间轮 3 绝对时间和相对时间 4 需要重复执行多次的任务 5 同一时刻存在多个任务 6 时间轮的数据结构 7 时间刻度不够用怎么办? 7.1 增大时间轮的刻度 7. ...

  2. 从 Kafka 看时间轮算法设计

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:https://juejin.cn/post/7047405443961847816 前言 Kafka 中有很多延时操作,比如 ...

  3. java 时间轮算法_时间轮算法(TimingWheel)是如何实现的?

    前言 我在2. SOFAJRaft源码分析-JRaft的定时任务调度器是怎么做的?这篇文章里已经讲解过时间轮算法在JRaft中是怎么应用的,但是我感觉我并没有讲解清楚这个东西,导致看了这篇文章依然和没 ...

  4. 原 荐 简单说说Kafka中的时间轮算法

    零.时间轮定义简单说说时间轮吧,它是一个高效的延时队列,或者说定时器.实际上现在网上对于时间轮算法的解释很多,定义也很全,这里引用一下 朱小厮博客 里出现的定义:参考下图,Kafka中的时间轮(Tim ...

  5. 时间轮算法解析(Netty HashedWheelTimer源码解读)

    1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...

  6. 心跳超时时间设置_定时器实现之时间轮算法

    前言 在看这篇文章的时候对其中超时控制一块儿有点好奇.通过时间轮来控制超时?啥是时间轮?怎么控制的?文章会先介绍常见的计时超时处理,再引入时间轮介绍及 netty 在实现时的一些细节,最后总结下实现的 ...

  7. java 时间轮算法_时间轮算法解析(Netty HashedWheelTimer源码解读)

    1.背景 时间轮算法可以用于高效的执行大量的定时任务. 在Netty中的一个典型应用场景是判断某个连接是否idle,如果idle(如客户端由于网络原因导致到服务器的心跳无法送达),则服务器会主动断开连 ...

  8. TimeWheel时间轮算法原理及实现(附源码)

    时间轮算法原理及实现 前言 1.时间轮核心 2.简单定时器 3.任务队列 4.优化任务队列 5.简单时间轮 6.多层时间轮 前言  在各种业务场景中,我们总是会需要一些定时进行一些操作,这些操作可能是 ...

  9. 时间轮算法(TimingWheel)

    时间轮算法的应用非常广泛,在 Dubbo.Netty.Kafka.ZooKeeper.Quartz 的组件中都有时间轮思想的应用,甚至在 Linux 内核中都有用到. 其思想理论基础可以参考论文:ht ...

最新文章

  1. 2022-2028年中国钢筘行业市场研究及前瞻分析报告
  2. 20145129 《Java程序设计》第6周学习总结
  3. ML之LiR之PLiR:惩罚线性回归PLiR算法简介、分类、代码实现之详细攻略
  4. Xen和虚拟化技术学习指南
  5. android开发 RecyclerView 瀑布列表布局
  6. C#~异步编程续~.net4.5主推的awaitasync应用
  7. STL源码剖析 算法章节 算法总览
  8. git subtree 管理项目子模块
  9. Linux学习笔记 --网络配置及进程管理
  10. 【转】如何查看linux版本 如何查看LINUX是多少位
  11. CSDN CODE 将于本月底彻底关闭,请尽快迁移到码云
  12. 工信部定级备案和等保备案有什么区别
  13. PL/SQL Oracle恢复默认界面设置
  14. 如何快速将jpg格式文件转换成bmp格式
  15. LTE CQI优化提升方法
  16. Github 学习 (整理自http://stormzhang.com/github/2016/06/04/learn-github-from-zero4/ 张哥学Git)
  17. 如何理解实践标准是确定性和不确定性的统一
  18. H ICPC Standings
  19. cecs计算机科学与技术,发布12个正宗IEEE/EI会议 (6月30-7月25号投稿截止) - 学术会议 - 小木虫 - 学术 科研 互动社区...
  20. DTCC呼吁银行和监管机构帮助解决区块链安全问题

热门文章

  1. 口碑预点单正餐先后付承接端哪些版本支持?
  2. php 元字符与转义,正则表达式中普通转义字符和元字符
  3. Unity WEBGL设置浏览器全屏
  4. 关于vs编译器 /GZ 选项的意思
  5. 发光二极管的keil代码c语言,用Keil点亮一个发光二极管
  6. 逆水寒跑商时服务器维护,逆水寒跑商路线推荐 合适的路线让你事半功倍
  7. 聊聊从逻辑门到操作系统的计算机
  8. 为什么我要反对北大青鸟[转自老赵]
  9. Android开发 系统服务,android 系统服务 开发
  10. C++的sort函数对于vector排序