.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("死信");

基本上,只要沒有被執行的任務,都會被取消執行的。

效果圖

24e3a1a07fe01bc43f283fae071683b6.gif

代碼詳解

先看看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

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/285211.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/285211.shtml
英文地址,請注明出處:http://en.pswp.cn/news/285211.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

phpstorm config include paths for swoole

配置phpstorm 當你寫swoole 類或者函數時會自動補全 https://github.com/swoole/ide-helper.git 克隆下這個工具包 點加&#xff0c;然后指定你下載好的工具包路徑&#xff0c;點ok 本文轉自 skinglzw 51CTO博客&#xff0c;原文鏈接&#xff1a;http://blog.51cto.com/sking…

C語言試題150之八進制轉換為十進制

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:八進制轉換為十進制 2 、溫馨…

JavaScript全面學習(中階)

1.typeof操作符總是返回一個字符串&#xff1a; typeof 123; // number typeof NaN; // number typeof str; // string typeof true; // boolean typeof undefined; // undefined typeof Math.abs; // function typeof null; // object typeof []; // object typeof {}; // obj…

【ArcGIS風暴】ArcGIS創建柵格數據集色彩映射表案例--以GlobeLand30土地覆蓋數據為例

矢量數據快速符號化&#xff0c;可以將常用的樣式保存到樣式符號庫&#xff0c;柵格數據快速符號化&#xff0c;需要創建色彩映射表。本文以GlobeLand30土地覆蓋數據為例&#xff0c;詳解ArcGIS中創建與使用色彩映射表。 文章目錄一、 ArcGIS色彩映射表介紹二、土地覆蓋數據色彩…

Visual Studio 2019 16.3.10 初體驗

Visual Studio 2019 版本 16.3.10 發布時間&#xff1a;2019 年 11 月 20 日 官網地址&#xff1a;https://visualstudio.microsoft.com/zh-hans/vs/ 介紹&#xff1a; https://devblogs.microsoft.com/visualstudio/dot-net-core-support-in-visual-studio-2019-version-16…

【ArcGIS風暴】GlobeLand30全球數據處理教程(批量投影轉換、無效值處理、拼接)

本文講述GlobeLand30全球數據批處理流程&#xff0c;主要步驟包括&#xff1a;批量分幅投影轉換、批量分幅無效值處理、批量圖幅拼接和成品展示。由于圖幅數目和數據量較大&#xff0c;本文是采用Python代碼批量實現的&#xff0c;有關Python的基本操作及處理案例&#xff0c;可…

Docker 私有倉庫的搭建

Docker在2015年推出了distribution項目&#xff0c;即Docker Registry 2。相比于old registry&#xff0c;Registry 2使用Go實現&#xff0c;在安全性、性能方面均有大幅改進。Registry設計了全新的Rest API&#xff0c;并且在image存儲格式等方面不再兼容于old Registry。去年…

請查收.NET MAUI 的最新學習資源

點擊上方藍字關注我們&#xff08;本文閱讀時間&#xff1a;3分鐘)2022 年 5 月 23 日&#xff0c;.NET MAUI 正式發布。.NET MAUI 為您提供了一流的跨平臺 UI 堆棧&#xff0c;面向 Android、iOS、macOS 和 Windows。我們很高興地宣布&#xff0c;有幾種不同的學習 .NET MAUI …

C語言試題151之求 0到7 所能組成的奇數個數。

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:求 0—7 所能組成的奇數個數…

騰訊2016春招之算法編程解析

第一道題&#xff1a;求有刪除情況的最長回文子串 題目&#xff1a; 解題思路&#xff1a; 這個題嚴格意義上來說&#xff0c;刪除了字符就談不上回文串了&#xff0c;既然有刪除&#xff0c;那估計考察的不是回文串&#xff0c;而是其他的&#xff0c;但是這個東西又有回文串的…

Windows下Visual studio 2013 編譯 Audacity

編譯的Audacity版本為2.1.2&#xff0c;由于實在windows下編譯&#xff0c;其源代碼可以從Github上取得 git clone https://github.com/audacity/audacity。 1. 編譯WxWidgets Audacity使用wxWidgets作為GUI的框架&#xff0c;Audacity2.1.2需要wxWidgets 3.0.2&#xff0c;所以…

[轉]解決Android studio升級到3.5的一些問題

最近Android studio升級到最新的3.5以后&#xff0c;出現了很多問題&#xff0c;記錄一下&#xff1a; 1.NDK Resolution Outcome: Project settings: Gradle model version5.4.1, NDK version is UNKNOWN 這個是因為升級到3.5以后&#xff0c;原來的ndk被刪除了&#xff0c;在…

【EPS精品教程】EPS2016三維測圖版安裝教程(附EPS2016安裝包下載地址)

文章目錄 一、安裝過程二、軟件安裝包下載EPS地理信息工作站是北京清華山維新技術開發有限公司歷經十五年精心研發和打造,為滿足“以地理信息服務為中心”的信息化測繪生產需求而推出的測繪生產活動多種業務模塊集成化軟件系統。主要功能有: (1)測繪與地理信息多業務模塊集…

據廖雪峰python3教程----python學習第十三天

在OOP程序設計中&#xff0c;當我們定義一個class的時候&#xff0c;可以從某個現有的class繼承&#xff0c;新的class稱為子類&#xff08;Subclass&#xff09;&#xff0c;而被繼承的class稱為基類、父類或超類&#xff08;Base class、Super class&#xff09;。 編寫一個名…

《增廣賢文》

&#xff08;《增廣賢文》&#xff09;&#xff0c;并非吾原創。其中人生之道理&#xff0c;今之看來&#xff0c;雖有偏激之處&#xff0c;未嘗不有警醒之用。吾輩取精去糟&#xff0c;察納雅言即可。———————————————————————————————————…

禁錮自己的因素,原來有這么多

2022年的7月&#xff0c;朋友圈都能看到喜慶的時刻&#xff0c;慶祝香港回歸25周年&#xff0c;這確實是一個具有偉大里程碑的意義。同時也是建黨101周年&#xff0c;滿滿的榮譽感&#xff0c;隔著朋友圈都能感受到喜慶。家事國事天下事&#xff0c;事事關心&#xff0c;關心但…

C語言試題152之一個偶數總能表示為兩個素數之和

??個人主頁:個人主頁 ??系列專欄:C語言試題200例 ??推薦一款模擬面試、刷題神器?? 點擊跳轉進入網站 ?作者簡介:大家好,我是碼莎拉蒂,CSDN博客專家(全站排名Top 50),阿里云博客專家、51CTO博客專家、華為云享專家 1、題目 題目:一個偶數總能表示為兩個素數…

[轉]Xshell連接win10 Linux子系統

配置SSH服務&#xff1a; sudo apt-get remove --purge openssh-server ## 先刪ssh sudo apt-get install openssh-server ## 在安裝ssh sudo rm /etc/ssh/ssh_config ## 刪配置文件&#xff0c;讓ssh服務自己想辦法鏈接 sudo service ssh --full…

有兩個地方,用到了javabean對象和屬性字符串值之間的轉換

1.有兩個地方&#xff0c;用到了javabean對象和屬性字符串值之間的轉換 2.一個是接入層spring mvc&#xff0c;將json字符串參數轉換為javaBean。通過RequestBody javaBean方式 3.另一個是&#xff0c;mybatis中javeBean對象與數據庫字段值之間的轉換。 在sql語句的insert/upda…

【EPS精品教程】EPS2016三維測圖軟件常用快捷鍵(建議收藏)

EPS2016三維測圖軟件常用快捷鍵(建議收藏) 狀 態鍵盤位置功能名稱功能描述選擇Shift拖點按下鼠標左鍵移動光標,將目標點拖到其他位置C閉合使打開的當前線閉合,閉合的當前線打開X回退一點從當前點回退一點Shift+X回退多點從當前點開始刪除多點(到光標指向點)Ctrl+T刪除刪除當…