簡易任務調度實現--可用於windows服務/asp.net網站執行后台計算


在項目開發中經常會遇到后台定時任務調度執行計算的需求,為此我實現了一個簡易的任務調度框架。

首先,我只實現的簡易調度框架,原則上在同一時間點只執行一個任務,實現在每天指定的時間段內執行一次或固定頻率(只是相對固定)執行多次任務。

其次,這個簡易框架可用於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)
{

}


}

這此代碼已經在項目中使用,已經通過本人多次測試。

完.





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM