共计 6054 个字符,预计需要花费 16 分钟才能阅读完成。
💻 前言
卷了,卷了,卷了,最近太卷。。。这篇文章写了好几天了,因为同类型文章太多,排期到明天公布。切实不想卷,得罪了!各位定时工作开源大佬们!
.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);
🌴 性能参考
FreeScheduler | Quartz.net | FluentScheduler | HashedWheelTimer |
---|---|---|---|
(500,000 Tasks + 10s) | (500,000 Tasks + 10s) | (500,000 Tasks + 10s) | (500,000 Tasks + 10s) |
383M | 1700+M | StackOverflow | 213M |
70563.6066ms | 50692.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/im | MIT |
FreeRedis | Redis SDK | https://github.com/2881099/Fr… | MIT |
csredis | https://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 |
FreeSql | ORM | https://github.com/dotnetcore… | MIT |
FreeSql.Cloud | 分布式 tcc/saga | https://github.com/2881099/Fr… | MIT |
FreeSql.AdminLTE | 低代码后盾生成 | https://github.com/2881099/Fr… | MIT |
FreeSql.DynamicProxy | 动静代理 | https://github.com/2881099/Fr… | 学习用处 |
须要的请拿走,这些都是最近几年的开源作品,以前更早写的就不发了。