最近有一个需求, 从网页上传一个文本包到后台处理, 处理时长可能在几分钟到几十分钟. 原来的方案就是直接接收一个 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.Ca che.NoSlidingExpiration);
- }
- }
3. 轮询处理
- public string CheckProcState(){
- string sessionId = Session.SessionID;
- Cache cache = new Cache();
- Result result = cache.GetCache<Result>(sessionId+"result");
- return result.ToJson();
- }
好啦, 大体过程就是这样了, 欢迎大家指正, 也欢迎讨论其他处理长耗时任务的可具体实施的思路.
来源: http://www.jianshu.com/p/3b075db3b8ff