最近有一個需求,從網頁上傳一個文本包到後臺處理,處理時長可能在幾分鐘到幾十分鐘。原來的方案就是直接接收一個ajax請求處理數據,然後返回。遇到的問題是:經過十幾分鐘的處理後,後臺返回結果到前端,前端收不到該結果了。我想應該是http連接超時了,除非長連接,沒有哪個請求可以這樣無限制地等待。於是着手改進方案,先說一下思路:
1.前端上傳文件到後臺後,後臺開啓一個子線程處理耗時任務,主線程直接返回結果給前端,當前請求結束,無須等待子任務的處理結果。注意這裏的返回結果只是表示文件上傳成功,是一個階段性的結果而已。
2.前端開啓一個輪詢,每隔一秒查一下當前任務的處理進度,直到任務處理結束。
回答一下這個思路中的幾個關鍵點
1.輪詢檢查的依據是什麼?後臺根據什麼來知道當前是誰在查詢?答案:Session.對Session不太瞭解的同學可以再做一下功課,這裏不展開。
2.主線程和新開的子線程之間是需要交換數據的,包括子線程和查詢線程之間也是需要交換數據的,這個交換數據是用什麼來實現?答案:HttpRuntime Cache,對這個不熟悉的也做一下功課,這裏簡單理解爲就是一塊可以共享數據的內存區域。
好了,思路和關鍵點都解決了,這裏再來貼一下關鍵點的代碼,讓大家有一個更清晰的認識
1.開啓子線程
//sessionid是作爲一個參數傳到子線程裏面去的,我們保存數據到cache中是以sessionid+關鍵字的形式來做key值,而session值是不能在子線程中直接獲取的,所以傳進去
String sessionId = Session.SessionID;
ThreadProc threadProc = new ThreadProc(sessionId);
Thread thread = new Thread(new ThreadStart(threadProc.process));
thread.IsBackground = true;
thread.Start();
子線程類:
class ThreadProc{
private string sessionId = "";
public ThreadProc(string sessionId){
this.sessionId = sessionId;
}
public void process(){
//這裏具體處理耗時任務
//保存結果
cache.WriteCache<Result>(result,sessionId+"result");
}
}
2.cache的存取
Cache cache = new Cache();
//讀取
Result result = cache.GetCache<Result>(sessionId+"result");
//保存
cache.WriteCache<Result>(result,sessionId+"result");
這裏Cache類是對原始HttpRuntime Cache的一次封裝,示例如下
public class Cache{
private static System.Web.Caching.Cache cache = HttpRuntime.Cache;
public T GetCache<T>(string cacheKey) where T:class{
if(cache[cacheKey] != null){
return (T)cache[cacheKey];
}
return default(T);
}
public void WriteCache<T>(T value,string cacheKey) where T:class{
cache.Insert(cacheKey,value,null,DateTime.Now.AddMinute(10),System.Web.Caching.Cache.NoSlidingExpiration);
}
}
3.輪詢處理
public string CheckProcState(){
string sessionId = Session.SessionID;
Cache cache = new Cache();
Result result = cache.GetCache<Result>(sessionId+"result");
return result.ToJson();
}
好啦,大體過程就是這樣了,歡迎大家指正,也歡迎討論其他處理長耗時任務的可具體實施的思路。