ASP.NET 中的定時執行任務
FluentScheduler is a better solution for cronjob in asp.net . https://www.nuget.org/packages/FluentScheduler
在一個網站中,經常需要設定一些任務能夠定時執行。
比如一些統計資料,例如網站會員的積分,積分的計算可能涉及很多因素和變數,而且需要累計很多條記錄才能得到結果,如果每次顯示會員資訊的時候,都是實時計算,那麼可想而知計算量非常大。如果還需要對所有會員的積分排序後在顯示列表,那就更是不可能完成的任務了。因此,顯然需要把積分的計算和顯示分開,計算不是實時的,當然這樣就會導致一定的不一致情況發生。這就要看對一致性的要求了。對於不贏房子不贏地的會員積分,稍微更新晚一點倒是無所謂的。
再比如,現在很多網站會根據會員的行為,頒發一些榮譽勳章,頒發的條件都是根據會員在網站行為來判斷的。顯然不能當一名會員在網站做了任何一個行為,都立即計算一次是否符合頒發各種勳章的條件。因此,也只能定期地計算一次。
因此關鍵就在於,非實時的計算會員積分,必定要求定時地執行,比如每半小時或一分鐘計算一次,具體時間間隔就根據業務的實際需要了。
那麼對於 ASP.NET 開發的網站,應該如何實現在後臺定時執行某個任務呢? 如果你在Google上用 cron job ASP.NET 搜尋,會搜到很多帖子,很顯眼的是 Stack Overflow 上的問題,被大多數人頂的答案是這樣的:
ASP.NET 不是完成這個工作的工具,你應該單獨做一個獨立的程式,然後通過設定為任務計劃,使該程式定期執行,要麼乾脆做成Service。而 ASP.NET 應該只被用來完成 請求/響應 模型的工作。
這個答案很有道理,確實應該如此。但是對於一個規模並不大的網站,如果能夠在 ASP.NET 內部解決這個問題,還是很有吸引力的。
實際上解決方案還是有的,並且是經過實際應用的,StackOverflow 的 Jeff Atwood 發過一個帖子,講解了一個方案,並且提到,StackOverflow 早期就是用這個方案每60秒鐘計算會員的徽章等資料的。當然,他也提到後隨著規模增大,他們已經不使用這個方案了。有興趣的可以參見:http://blog.stackoverflow.com/2008/07/easy-background-tasks-in-aspnet/
我這裡簡單描述一下這個方案,我用lambda表示式的方式改寫了一下,程式碼看起來簡單一些。
public static void AddTask(int seconds, Action todo)
{
HttpRuntime.Cache.Insert(
Guid.NewGuid().ToString(),
0,
null,
DateTime.Now.AddSeconds(seconds),
Cache.NoSlidingExpiration,
CacheItemPriority.NotRemovable,
(key, value, reason) =>
{
todo.Invoke();
AddTask(seconds, todo);
});
}
就這麼一個非常簡單的函式,然後在 global.asax 裡面的呼叫這個函式即可。
void x()
{
Debug.WriteLine(DateTime.Now);
}
void x2()
{
Debug.WriteLine("---" + DateTime.Now);
}
protected void Application_Start()
{
AddTask(40, x);
AddTask(60, x2);
//.......
}
上面的程式碼設定了兩個void型別的方法,然後在 Application_Start() 中設定二者的執行時間間隔,一個40秒執行一次,一個60秒執行一次。在IDE的output視窗中,可以看到執行的結果如下:
2013/5/12 18:09:00
---2013/5/12 18:09:20
2013/5/12 18:09:40
---2013/5/12 18:10:20
2013/5/12 18:10:20
2013/5/12 18:11:00
---2013/5/12 18:11:20
2013/5/12 18:11:40
2013/5/12 18:12:20
---2013/5/12 18:12:20
可以看到,一個40秒列印一行,另一個60秒列印一行。具體要做什麼,就看你的了!
需要說明的是,這個方案的原理是利用了ASP.NET的快取機制,向ASP.NET的快取集合中新增一個快取項,設定過期的時間,當到達這個時間的時候,會執行一個回撥函式,就把你要做的事情放到這個回撥函式裡,並且在執行要做的事兒之後,再次加入一個快取項,如此不斷地往復進行。
這裡存在一個問題就是,在預設情況下,ASP.NET 每20秒回收一次快取項,因此,這個方法不能把時間間隔設定的太小,我覺得至少分鐘級別比較合適。
最後需要再次提醒的是,這個方法可以算是一個 hack 方法,並不是一個常規的優雅的做法,在 Jeff Atwood 的帖子後面,很多人提出了反對意見,大家有興趣可以看一看。而且在這個帖子的半年多已後的2009年初,Stack Overflow 就不再使用這個方法,而改用更正常的方式來實現了。但是你要知道,Stack Overflow 的訪問量在初期發展異常迅猛,在2009年初的時候,Alexa 排名已經升到全世界的1000多名了。Stack Overflow 半年的路,很多網站可能要走很多年,甚至很多年也到不了,因為全世界也就1000個網站可以排到前1000名。
好了,希望這個小技巧對你有所幫助。說實話,這個技巧可以解決大問題滴。
相關文章
- PHP定時執行任務PHP
- spring執行定時任務Spring
- laravel框架任務排程(定時執行任務)Laravel框架
- PHP定時執行任務的實現PHP
- php後臺定時執行任務PHP
- java web每天定時執行任務JavaWeb
- Django配置celery執行非同步任務和定時任務Django非同步
- 定時間點執行任務的asp.net簡易解決辦法ASP.NET
- SpringBoot執行定時任務@ScheduledSpring Boot
- Laravel 定時任務突然無法執行Laravel
- kettle執行定時任務,kitchen.batBAT
- Android利用AlarmManager執行定時任務Android
- Ext.util.TaskRunner定時執行任務
- Springboot-之定時任務,啟動執行任務Spring Boot
- centOS crontab定時任務不執行的解決CentOS
- 『學了就忘』Linux系統定時任務 — 88、迴圈執行定時任務Linux
- linux設定crontab定時執行任務計劃Linux
- Linux中crontab定時任務未執行錯誤總結Linux
- 『學了就忘』Linux系統定時任務 — 87、只執行一次的定時任務Linux
- 【Awen】asp.net定時任務實現ASP.NET
- Java 中的定時任務(一)Java
- ubuntu上使用cron執行定時任務計劃Ubuntu
- 使用spring @Scheduled註解執行定時任務、Spring
- Spring Task 定時任務 - 多執行緒配置Spring執行緒
- 多執行緒-定時任務的多次執行程式碼體現執行緒行程
- Java實現終止執行緒池中正在執行的定時任務Java執行緒
- Linux下的crontab定時執行任務命令詳解Linux
- Linux系統中延時任務及定時任務Linux
- spring boot中的定時任務Spring Boot
- Spring Boot中得定時任務執行一段時間後突然停了Spring Boot
- Centos 7下利用crontab定時執行任務詳解CentOS
- CentOS Linux使用crontab執行定時任務詳解CentOSLinux
- centos7.2 利用crontab執行定時計劃任務CentOS
- 寶塔---伺服器終端執行定時任務伺服器
- 一個執行定時任務(Crontab)和任務佇列(Taskqueue)的 Python 小工具佇列Python
- 定時任務
- Laravel 是怎樣防止你的定時任務重複執行的Laravel
- Linux 執行定時任務後,Laravel 專案報錯LinuxLaravel