首页  ·  知识 ·  云计算
简易任务调度实现--可用于windows服务/asp.net网站执行后台计算
flysun/  博客园  综合  编辑:dezai   图片来源:网络
在项目开发中经常会遇到后台定时任务调度执行计算的需求,为此我实现了一个简易的任务调度框架。首先,我只实现的简易调度框架,原则上在同一时间点只执行一个任务,实现在每天指定的时间段内执
 在项目开发中经常会遇到后台定时任务调度执行计算的需求,为此我实现了一个简易的任务调度框架。首先,我只实现的简易调度框架,原则上在同一时间点只执行一个任务,实现在每天指定的时间段内执行一次或固定频率(只是相对固定)执行多次任务。
其次,这个简易框架可用于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)

{



}





}

这此代码已经在项目中使用,已经通过本人多次测试。

本文作者:flysun/ 来源:博客园
CIO之家 www.ciozj.com 微信公众号:imciow
   
免责声明:本站转载此文章旨在分享信息,不代表对其内容的完全认同。文章来源已尽可能注明,若涉及版权问题,请及时与我们联系,我们将积极配合处理。同时,我们无法对文章内容的真实性、准确性及完整性进行完全保证,对于因文章内容而产生的任何后果,本账号不承担法律责任。转载仅出于传播目的,读者应自行对内容进行核实与判断。请谨慎参考文章信息,一切责任由读者自行承担。
延伸阅读