前言

卷了,卷了,卷了,最近太卷。。。这篇文章写了好几天了,因为同类型文章太多,排期到明天公布。切实不想卷,得罪了!各位定时工作开源大佬们!

.NET 定时组件生态切实太强大了,写下此文只心愿能供大家多一个抉择,不想反复造轮子,切实是无缘无故。

高中读书那会,盛大传奇是最火爆的网络游戏,我和我的同学们都对它有过沉迷,甚至到下班几年之后,对它依然有一种莫名的情怀。

干咱们这行忙的时候要加班,闲的时候也很闲,在我已经很闲的一份工作里,为了情怀去钻研了传奇sf引擎,在简洁的脚本代码里我发现了一个宝藏:流动定时工作。除了以秒单位定时触发,还能够设置每月某天、每周某天、每天某工夫,在 .net framework 3.0 广泛还在应用 Timer 的年代,我一下子被惊艳到了,于是利用 Timer 仿着性能本人实现了一版 .NET 定时工作性能类。

一开始只是一个类间接放进我的项目内应用,从未公布过 nuget 版本。打从 2016 年接触 .net core 以来,励志为开源生涯添砖加瓦,这才有了正式公布的念头。我已经保护过 csredis(因原作者不保护所以公布为 CSRedisCore),醉生梦死从零到一开源 FreeSql,重构 RedisClient 公布的 FreeRedis,聊天架构 IMCore。。。等等。

因 FreeSql 应用需要编写了乏味的开源组件 IdleBus,写完后发现它的特点还蛮适宜用来扩大定时工作,于时重构了一个版本命名 IdleScheduler,在 2020 年公布开源,前不久已正式改名为 FreeScheduler。

经验了十几年的应用需要和革新进化,切实是"食之无味,弃之可惜"。还是供大家多一个抉择吧!


⛳ 次要劣势

FreeScheduler 轻量化定时任务调度,反对长期的延时工作和反复循环工作(可长久化),可按秒,每天/每周/每月固定工夫,自定义距离执行(CRON表达式),反对 .NET Framework 4.0,.NETCore2.1 +,Xamarin、MAUI 等平台 运行环境。

特色性能之一:FreeScheduler 反对一个工作设置 [5,5,30,30,60] 不同的定时距离,任何一次胜利都可完结整个工作。

scheduler.AddTask("比武大会", "json", new [] { 5, 5, 30, 30, 60 });class MyTaskHandler : FreeScheduler.TaskHandlers.TestHandler{    public override void OnExecuting(Scheduler scheduler, TaskInfo task)    {        Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");        if (task.Topic == "比武大会")        {            try            {                //todo..                //任何一次不报错,强制使工作实现                task.Status = TaskStatus.Completed;            }            finaly            {            }        }    }}

轻量化解释:理解 FreeRedis、FreeSql、csredis 的人都晓得,咱们公布的开源我的项目是绿色著称,零依赖公布后只有一个DLL,不会造成使用者我的项目依赖抵触,反对 .NET 4.0 堪称屎山我的项目的救星。当初还有很多.NET FX4.0 的我的项目,这些我的项目因历史遗留起因或硬件限度,不能更换 .NET Core 版本。因而这些我的项目很难应用到现有的开源库,不能应用牢靠的开源库,那么很多时候都要自行实现,在沉积代码的同时,我的项目也有可能越来越乱,代码越来越渣,我的项目逐步变得不稳固。


⚡ 疾速开始

开源地址:https://github.com/2881099/FreeScheduler

演示代码:https://github.com/2881099/Fr...

dotnet add package FreeScheduler

或者

Install-Package FreeScheduler
public static Scheduler scheduler = new Scheduler(new MyTaskHandler()); //单例模式,尽量保障只创立一次

长期工作

长期工作属于内存工作,不可长久化。

void Callback(){    Console.WriteLine("工夫到了");    scheduler.AddTempTask(TimeSpan.FromSeconds(10), Callback); //设置下一次定时}scheduler.AddTempTask(TimeSpan.FromSeconds(10), Callback);//如果是一次性工作,能够这样写:scheduler.AddTempTask(TimeSpan.FromSeconds(10), () =>{    Console.WriteLine("工夫到了");});
Method阐明
string AddTempTask(TimeSpan, Action)创立长期的延时工作,返回 id
bool RemoveTempTask(string id)删除工作(长期工作)
bool ExistsTempTask(string id)判断工作是否存在(长期工作)
int QuantityTempTask工作数量(长期工作)

本地环境测试 50万 个长期工作,占用内存 383M,全副执行实现耗时 70秒。

  • Quartz.net 内存溢出,耗时 50秒
  • FluentScheduler 占用内存 1700M,耗时 未知
  • HashedWheelTimer 占用内存 213M,耗时 34秒

我尝试过把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高(600兆),起因是 FreeScheduler 性能须要占用更多资源。


循环工作

  • 长期工作是一次性触发,触发体是 Action 委托
  • 循环工作是周期性反复触发,触发体是 FreeScheduler.ITaskHandler,如上述 MyTestHandler
Method阐明
void ctor(ITaskHandler)指定任务调度器(单例)
string AddTask(string topic, string body, int round, int seconds)创立循环定时工作,返回 id
string AddTask(string topic, string body, int[] seconds)创立每轮距离不同的定时工作,返回 id
string AddTaskRunOnDay(..)创立每日循环工作,指定utc工夫,返回 id
string AddTaskRunOnWeek(..)创立每周循环工作,指定utc工夫,返回 id
string AddTaskRunOnMonth(..)创立每月循环工作,指定utc工夫,返回 id
string AddTaskCustom(string topic, string body, string expression)创立自定义工作,返回 id
bool RemoveTask(string id)删除工作
bool ExistsTask(string id)判断工作是否存在
bool ResumeTask(string id)复原已暂停的工作
bool PauseTask(string id)暂停正在运行的工作
TaskInfo[] FindTask(lambda)查问正在运行中的工作
int QuantityTask工作数量
//每5秒触发,执行N次var id = scheduler.AddTask("topic1", "body1", round: -1, 5);//每次 不同的距离秒数触发,执行6次var id = scheduler.AddTask("topic1", "body1", new [] { 5, 5, 10, 10, 60, 60 });//每天 20:00:00 触发,指定utc工夫,执行N次var id = scheduler.AddTaskRunOnDay("topic1", "body1", round: -1, "20:00:00");//每周一 20:00:00 触发,指定utc工夫,执行1次var id = scheduler.AddTaskRunOnWeek("topic1", "body1", round: 1, "1:20:00:00");//每月1日 20:00:00 触发,指定utc工夫,执行12次var id = scheduler.AddTaskRunOnMonth("topic1", "body1", round: 12, "1:20:00:00");

Cron

因为 .NET Cron 组件广泛不反对年,因而 FreeScheduler 默认没有集成,然而很容易扩大实现,如下:

var id = scheduler.AddTaskCustom("topic1", "body1", "0/1 * * * * ? ");public static Scheduler scheduler = new Scheduler(new MyTaskHandler(), new CronCustomHandler()); //单例模式,尽量保障只创立一次class CronCustomHandler : FreeScheduler.ITaskIntervalCustomHandler{    public TimeSpan? NextDelay(TaskInfo task)    {        //利用 cron 性能库解析 task.IntervalArgument 失去下一次执行工夫        //与以后工夫相减,失去 TimeSpan,若返回 null 则工作实现        return TimeSpan.FromSeconds(5);    }}

长久化

FreeScheduler 把工作分为两种类型,长期工作和循环工作,留神长期工作不反对长久化。

以后已反对 数据库或Redis 长久化实现,各有优缺点:

  • 数据库,性能低,不便接入工作治理(后盾管理系统)
  • Redis,性能高,因为分页的特点,接入工作治理性能略难

应用长久化只须要把 Scheduler 结构参数批改,如下:

var fsql = new FreeSql.FreeSqlBuilder()    .UseConnectionString(FreeSql.DataType.Sqlite, "data source=task.db;max pool size=5")    .UseAutoSyncStructure(true)    .UseNoneCommandParameter(true)    .UseMonitorCommand(cmd => Console.WriteLine($"=========sql: {cmd.CommandText}\r\n"))    .Build();Scheduler scheduler = new Scheduler(new MyTaskHandler(fsql));class MyTaskHandler : FreeScheduler.TaskHandlers.FreeSqlHandler{    public MyTaskHandler(IFreeSql fsql) : base(fsql) { }    public override void OnExecuting(Scheduler scheduler, TaskInfo task)    {        Console.WriteLine($"[{DateTime.Now.ToString("HH:mm:ss.fff")}] {task.Topic} 被执行");    }}

Redis 长久化请装置:

dotnet add package FreeScheduler.TaskHandlers.FreeRedis

Install-Package FreeScheduler.TaskHandlers.FreeRedis


治理工作

// 应用 FreeSql 或者 SQL 查问 TaskInfo、TaskLog 两个表进行分页显示fsql.Select<TaskInfo>().Count(out var total).Page(pageNumber, 30).ToList();fsql.Select<TaskLog>().Count(out var total).Page(pageNumber, 30).ToList();//暂停工作scheduler.PauseTask(id);//复原暂停的工作scheduler.ResumeTask(id);//删除工作scheduler.RemoveTask(id);

性能参考

FreeSchedulerQuartz.netFluentSchedulerHashedWheelTimer
(500,000 Tasks + 10s)(500,000 Tasks + 10s)(500,000 Tasks + 10s)(500,000 Tasks + 10s)
383M1700+MStackOverflow213M
70563.6066ms50692.5365ms未知33697.8758ms

FluentScheduler 单个 Registry 测试失常,但目测单线程执行(距离1-10ms),处理速度不现实 View Code

我尝试把 FreeScheduler 内核改成 HashedWheelTimer 内存占用更高(600兆),论断:FreeScheduler 性能须要占用更多资源


结束语

.NET 定时工作组件太多了,以至于过来这些年都还没有正式推广过,心愿能帮忙到有需要的敌人。

开源地址:https://github.com/2881099/FreeScheduler


作者是什么人?

作者是一个入行 18年的老批,他目前写的.net 开源我的项目有:

开源我的项目形容开源地址开源协定
ImCore聊天零碎架构https://github.com/2881099/imMIT
FreeRedisRedis SDKhttps://github.com/2881099/Fr...MIT
csredishttps://github.com/2881099/cs...MIT
FightLandlord斗DI主网络版https://github.com/2881099/Fi...学习用处
FreeScheduler定时工作https://github.com/2881099/Fr...MIT
IdleBus闲暇容器https://github.com/2881099/Id...MIT
FreeSqlORMhttps://github.com/dotnetcore...MIT
FreeSql.Cloud分布式tcc/sagahttps://github.com/2881099/Fr...MIT
FreeSql.AdminLTE低代码后盾生成https://github.com/2881099/Fr...MIT
FreeSql.DynamicProxy动静代理https://github.com/2881099/Fr...学习用处

须要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。