改变之前的前言,这次咱这样写:
一个习惯只需十天的坚持就可以养成,坏习惯也不例外!吸烟喝酒的我能否做到十天不吸烟喝酒呢?
呵呵
养成习惯关键还要看决心和意志力
恩,努力控烟吧!
废话说完了,就进入咱们的小程序:Job作业。
我这里所说的Job作业并没有 Quartz 或者 Quartz.Net 那么高大尚,今天和大家介绍的作业是一个非常非常轻量级的框架,与其说框架倒不如说是一个只有不足千行的代码!
哈哈
如下:
按照我的步骤,一起来构建一个 Job 作业调度的小项目,
步骤一:新建一个解决方案,姑且命名为Job吧,如下:
此解决方案有两个项目,一个是Job控制台项目,一个是CronJob类库,
步骤二:复制粘贴下边的代码
控制台 Program.cs 代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using CronJob;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.Threading.Tasks;namespace Job{ class Program { private static readonly CronMon CronMon = new CronMon(); static void Main(string[] args) { Start(); while (true) { Console.WriteLine(string.Format("{0}: Running", DateTime.Now.ToString("s"))); Thread.Sleep(60 * 1000); } } public static void Start() { Init(); CronMon.Start(); } //Cron 表达式范例 //TODO 移到配置文件里 //* * * * * = Minutes Hours Day-of-Month Month Day-of-Week //每隔1分钟执行一次:*/1 * * * //每天23点执行一次:0 23 * * //每天凌晨1点执行一次:0 1 * * //每月1号凌晨1点执行一次:0 1 1 * //在26分、29分、33分执行一次:26,29,33 * * * //每天的0点、13点、18点、21点都执行一次: 0 0,13,18,21 * * private static void Init() { CronMon.AddJob(new JobFoobar("*/1 * * *")); CronMon.AddJob(new JobFoobar2("*/1 * * *")); } public static void Abort() { CronMon.Stop(); } }}
CronJob类库代码如下:
CronJob类库中有两个文件夹,一个是基类文件夹(Base),一个是你的作业文件夹(Jobs):
关于基类文件夹没什么可说的,关于作业文件夹是指你的项目中需要做调度的任务都可以写成Job放在这个文件夹中,
基类代码如下:
CronJobBase.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System;using System.Threading;namespace CronJob{ public interface ICronJob { void Run(DateTime dateTime); void Abort(); } public class CronJobBase : ICronJob { private readonly object _lock = new object(); private readonly CronSchedule _cronSchedule; private Thread _thread; public CronJobBase(string schedule) { _cronSchedule = new CronSchedule(schedule); } public void Run(DateTime dateTime) { lock (_lock) { if (!_cronSchedule.IsTime(dateTime)) return; if (_thread!= null && _thread.ThreadState == ThreadState.Running) return; _thread = new Thread(ExecuteHandler); _thread.Start(); } } public void Abort() { _thread.Abort(); } private void ExecuteHandler() { try { Execute(); } catch (Exception ex) { Console.WriteLine("Error:", ex); } } protected virtual void Execute() { } }}
CronMon.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System;using System.Collections.Generic;using System.Timers;using System.Threading;namespace CronJob{ public interface ICronMon { void AddJob(ICronJob job); void Start(); void Stop(); } public class CronMon : ICronMon { private readonly System.Timers.Timer _timer = new System.Timers.Timer(30000); private readonly List_cronJobs = new List (); private DateTime _last = DateTime.Now; public CronMon() { _timer.AutoReset = true; _timer.Elapsed += timer_elapsed; } public void AddJob(ICronJob job) { _cronJobs.Add(job); } public void Start() { _timer.Start(); } public void Stop() { _timer.Stop(); foreach (var cronJob in _cronJobs) { var job = (CronJobBase) cronJob; job.Abort(); } } private void timer_elapsed(object sender, ElapsedEventArgs e) { if (DateTime.Now.Minute != _last.Minute) { _last = DateTime.Now; foreach (ICronJob job in _cronJobs) job.Run(DateTime.Now); } } }}
CronSchedule.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System;using System.Collections.Generic;using System.Text.RegularExpressions;namespace CronJob{ public interface ICronSchedule { bool IsValid(string expression); bool IsTime(DateTime dateTime); } public class CronSchedule : ICronSchedule { private static readonly Regex DividedRegex = new Regex(@"(\*/\d+)"); private static readonly Regex RangeRegex = new Regex(@"(\d+\-\d+)\/?(\d+)?"); private static readonly Regex WildRegex = new Regex(@"(\*)"); private static readonly Regex ListRegex = new Regex(@"(((\d+,)*\d+)+)"); private static readonly Regex ValidationRegex = new Regex(DividedRegex + "|" + RangeRegex + "|" + WildRegex + "|" + ListRegex); private readonly string _expression; public List Minutes; public List Hours; public List DaysOfMonth; public List Months; public List DaysOfWeek; public CronSchedule() { } public CronSchedule(string expressions) { _expression = expressions; Generate(); } private bool isValid() { return IsValid(_expression); } public bool IsValid(string expression) { MatchCollection matches = ValidationRegex.Matches(expression); return matches.Count > 0;//== 5; } public bool IsTime(DateTime dateTime) { return Minutes.Contains(dateTime.Minute) && Hours.Contains(dateTime.Hour) && DaysOfMonth.Contains(dateTime.Day) && Months.Contains(dateTime.Month) && DaysOfWeek.Contains((int)dateTime.DayOfWeek); } private void Generate() { if (!isValid()) return; MatchCollection matches = ValidationRegex.Matches(_expression); GenerateMinutes(matches[0].ToString()); if (matches.Count > 1) GenerateHours(matches[1].ToString()); else GenerateHours("*"); if (matches.Count > 2) GenerateDaysOfMonth(matches[2].ToString()); else GenerateDaysOfMonth("*"); if (matches.Count > 3) GenerateMonths(matches[3].ToString()); else GenerateMonths("*"); if (matches.Count > 4) GenerateDaysOfWeeks(matches[4].ToString()); else GenerateDaysOfWeeks("*"); } private void GenerateMinutes(string match) { Minutes = GenerateValues(match, 0, 60); } private void GenerateHours(string match) { Hours = GenerateValues(match, 0, 24); } private void GenerateDaysOfMonth(string match) { DaysOfMonth = GenerateValues(match, 1, 32); } private void GenerateMonths(string match) { Months = GenerateValues(match, 1, 13); } private void GenerateDaysOfWeeks(string match) { DaysOfWeek = GenerateValues(match, 0, 7); } private List GenerateValues(string configuration, int start, int max) { if (DividedRegex.IsMatch(configuration)) return DividedArray(configuration, start, max); if (RangeRegex.IsMatch(configuration)) return RangeArray(configuration); if (WildRegex.IsMatch(configuration)) return WildArray(configuration, start, max); if (ListRegex.IsMatch(configuration)) return ListArray(configuration); return new List (); } private List DividedArray(string configuration, int start, int max) { if (!DividedRegex.IsMatch(configuration)) return new List (); List ret = new List (); string[] split = configuration.Split("/".ToCharArray()); int divisor = int.Parse(split[1]); for (int i = start; i < max; ++i) if (i % divisor == 0) ret.Add(i); return ret; } private List RangeArray(string configuration) { if (!RangeRegex.IsMatch(configuration)) return new List (); List ret = new List (); string[] split = configuration.Split("-".ToCharArray()); int start = int.Parse(split[0]); int end = 0; if (split[1].Contains("/")) { split = split[1].Split("/".ToCharArray()); end = int.Parse(split[0]); int divisor = int.Parse(split[1]); for (int i = start; i < end; ++i) if (i % divisor == 0) ret.Add(i); return ret; } else end = int.Parse(split[1]); for (int i = start; i <= end; ++i) ret.Add(i); return ret; } private List WildArray(string configuration, int start, int max) { if (!WildRegex.IsMatch(configuration)) return new List (); List ret = new List (); for (int i = start; i < max; ++i) ret.Add(i); return ret; } private List ListArray(string configuration) { if (!ListRegex.IsMatch(configuration)) return new List (); List ret = new List (); string[] split = configuration.Split(",".ToCharArray()); foreach (string s in split) ret.Add(int.Parse(s)); return ret; } }}
作业代码如下:
Job1.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using CronJob;using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CronJob{ public class JobFoobar : CronJobBase { public JobFoobar(string schedule) : base(schedule) { } protected override void Execute() { Console.WriteLine("作业开始执行"); //do your logic Console.WriteLine("我是一个简答的Job作业,编号为:1"); //do your logic Console.WriteLine("执行结束"); //throw new Exception("fake error"); } }}
Job2.cs
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
![](https://images.cnblogs.com/OutliningIndicators/ExpandedBlockStart.gif)
using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading.Tasks;namespace CronJob{ public class JobFoobar2 : CronJobBase { public JobFoobar2(string schedule) : base(schedule) { } protected override void Execute() { Console.WriteLine("作业开始执行"); //do your logic Console.WriteLine("我是一个简答的Job作业,编号为:2"); //do your logic Console.WriteLine("执行结束"); //throw new Exception("fake error"); } }}
OK,项目打造完成后,记得控制台项目引用基类项目,那么运行后,如下:
在我们的作业中设置的是每一分钟执行一次,
两分钟的时间,执行了两次!
OK,源码地址为:
@陈卧龙的博客