在项目开发中经常会遇到后台定时任务调度执行计算的需求,为此我实现了一个简易的任务调度框架。
首先,我只实现的简易调度框架,原则上在同一时间点只执行一个任务,实现在每天指定的时间段内执行一次或固定频率(只是相对固定)执行多次任务。
其次,这个简易框架可用于windows 服务或asp.net网站实现后台定时调度任务计算。
要实现任务调度,使用核心技术的就是System.Timers.Timer对象。
下面代码实现:
1.定义内部使用的任务类Task;
View Code
1 private class Task 2 { 3 public TimeSpan Start; //每天任务开始的时间点,从00:00开始算起 4 public TimeSpan End; //每天任务结束的时间点,从00:00开始算起 5 public bool Once = false; //指定任务是否每天只执行一次 6 public DateTime Executed = DateTime.MinValue; //任务在最后一次执行的时间点 7 public TimeSpan Interval; //任务执行频率 8 public Action action; //匿名委托,用于任务计算 9 public override string ToString() 10 { 11 return string.Format(@"Task({0}) Start:{1},End:{2},Once:{3},Interval:{4},Action:{5},Executed:{6}", this.GetHashCode(), this.Start, this.End, this.Once, this.Interval, this.action, this.Executed); 12 } 13 }
2.任务调试类的主要接口(核心功能)
View Code
class Schedule : IDisposable { private class Task { public TimeSpan Start; //每天任务开始的时间点,从00:00开始算起 public TimeSpan End; //每天任务结束的时间点,从00:00开始算起 public bool Once = false; //指定任务是否每天只执行一次 public DateTime Executed = DateTime.MinValue; //任务在最后一次执行的时间点 public TimeSpan Interval; //任务执行频率 public Action action; //匿名委托,用于任务计算 public override string ToString() { return string.Format(@"Task({0}) Start:{1},End:{2},Once:{3},Interval:{4},Action:{5},Executed:{6}", this.GetHashCode(), this.Start, this.End, this.Once, this.Interval, this.action, this.Executed); } }
/// <summary> /// 在每天指定的时间段内以相对固定的频率执行任务 /// </summary> /// <param name="start">任务开始时间点,从00:00开始算起</param> /// <param name="end">任务结束时间点,从00:00开始算起</param> /// <param name="interval">任务调试效率</param> /// <param name="action">匿名委托,用于任务计算</param> public void Execute(TimeSpan start, TimeSpan end, TimeSpan interval, Action action) { AddTask(new Task() { action = action, End = end, Interval = interval, Once = false, Start = start }); }
/// <summary> /// 在每天指定的时间段内执行一次任务 /// </summary> /// <param name="start">任务开始时间点,从00:00开始算起</param> /// <param name="end">任务结束时间点,从00:00开始算起</param> /// <param name="action">匿名委托,用于任务计算</param> public void ExecuteOnce(TimeSpan start, TimeSpan end, Action action) { AddTask(new Task() { action = action, End = end, Once = true, Start = start }); }
/// <summary> /// 开始调度任务 /// </summary> public void Start() { this.onGoing = true; this.timer.Enabled = true; }
/// <summary> /// 结束高度任务 /// </summary> public void Stop() { this.onGoing = false; this.timer.Enabled = false; }
private System.Timers.Timer timer;//timer对象,用于定时检时任务执行点 private volatile bool onGoing = false; //指示任务调度是否持续运行 private List<Task> tasks = new List<Task>(); //任务列表,用于任务排序
/// <summary> /// 构造函数,默认以5秒的频率检查任务执行时间点 /// </summary> public Schedule() : this(5000) {
}
/// <summary> /// 构造函数,默认以指定的频率检查任务执行时间点 /// </summary> /// <param name="interval"></param> public Schedule(double interval) { timer = new System.Timers.Timer(interval); timer.AutoReset = false; //这是整个框架实现的关键所在,后面会进一步说明 timer.Enabled = false; timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed); //用于检查任务时间点的匿名委托 }
/// <summary> /// 添加一个任务到任务列表 /// </summary> /// <param name="task"></param> private void AddTask(Task task) { if (task.Once == true) tasks.Insert(0, task); //每天一次的任务优先 else tasks.Add(task); }
/// <summary> /// 用于检查任务时间点的匿名委托 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e) { if (this.onGoing == true) //判断调度是否继续 { if (tasks.Count > 0) { int index = 0; while (true) { Task task = tasks[index++]; //获取任务列表中的第一个任务
if (this.onGoing == false) break; //判断调度是否继续
if (CompareTime(task)) //比较任务时间点 { ExecuteTask(task); //执行任务,同时更新任务最后执行时间点 SortTasks(); //对任务列表进行排序,确定下一次最先执行的任务 break; } } } }
if (this.onGoing == true)//判断调度是否继续 { this.timer.Enabled = true; //激活timer,在指定时间再进一次任务时间点检查 } }
/// <summary> /// 任务列表排序,将一次性的任务排在前面,将最近已执行的任务放在最后 /// </summary> private void SortTasks() { if (tasks.Count <= 1) return; tasks.Sort(new Comparison<Task>(delegate(Task Task0, Task Task1) { if (Task0.Once == true && Task1.Once == false) { return -1; }
if (Task0.Once = true && Task1.Once == true) { return Task0.Executed < Task1.Executed ? -1 : 1; }
if (Task0.Once == false && Task1.Once == true) { return 1; }
return Task0.Executed < Task1.Executed ? -1 : 1; }));
}
/// <summary> /// 比较任务时间点 /// </summary> /// <param name="task">任务</param> /// <returns></returns> private bool CompareTime(Task task) {
DateTime Now = DateTime.Now; //当前时间点
//计算任务在当天内开始执行时间 DateTime startTime = new DateTime(Now.Year, Now.Month, Now.Day, task.Start.Hours, task.Start.Minutes, task.Start.Seconds); //计算任务在当天内结束执行时间 DateTime endTime = new DateTime(Now.Year, Now.Month, Now.Day, task.End.Hours, task.End.Minutes, task.End.Seconds); //任务跨天执行,调整时间点 if (startTime > endTime) endTime += new TimeSpan(24, 0, 0);
//如果是每天一次的任务,而且已经执行过一次 if (task.Once == true && startTime <= task.Executed && task.Executed <= endTime) { return false; }
return startTime <= Now && Now <= endTime; //如果当前时间点,在任务执行时间段内,则返真 }
/// <summary> /// 执行任务 /// </summary> /// <param name="task"></param> private void ExecuteTask(Task task) { if (task.action != null) { //如果当前时间在任务执行频率内,则执行 if (task.Executed == DateTime.MinValue || DateTime.Now - task.Executed >= task.Interval) { task.action(); task.Executed = DateTime.Now; //更新任务最后执行时间 } } }
#region IDisposable Members
public void Dispose() { this.timer.Dispose(); }
#endregion }
3.在asp.net网站中调度任务
View Code
public class Global : System.Web.HttpApplication {
Schedule schedule = new Schedule(10000); /// <summary> /// IIS启动时 /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void Application_Start(object sender, EventArgs e) { //每天从11:30至17:30,每隔一分钟执行一次任务 schedule.Execute(new TimeSpan(11, 30, 0), new TimeSpan(17, 30, 0), new TimeSpan(0,1,0), delegate() { AutoQuery.Execute(); });
//每天从11:00至11:20,只执行一次任务 schedule.ExecuteOnce(new TimeSpan(11, 0, 0), new TimeSpan(11, 20, 0), delegate() { AutoQuery.PrepareTasks(); });
//开始任务调度 schedule.Start(); }
protected void Application_End(object sender, EventArgs e) { //停止调度任务 schedule.Stop(); }
protected void Session_Start(object sender, EventArgs e) {
}
protected void Application_BeginRequest(object sender, EventArgs e) {
}
protected void Application_AuthenticateRequest(object sender, EventArgs e) {
}
protected void Application_Error(object sender, EventArgs e) {
}
protected void Session_End(object sender, EventArgs e) {
}
}
这此代码已经在项目中使用,已经通过本人多次测试。
完.
|
请发表评论