1.为什么需要异步Action
池的模式一直是我们处理对象频繁创建、销毁时采取的一种策略。就像一个大型图书馆,当我们需要某种图书的时候只需要到里面寻找就可以了,使用完毕之后放回;而不是每次想要获取的时候通知印刷厂为我们印刷一本。ASP.NET对HTTP的请求处理也是采用了线程池的方式,每个web应用内部都维护着一个线程池,当请求到达之后ASP.NET会从线程池中取出一个空闲的线程来专门处理这次请求,请求结束之后线程也不是被直接销毁而是放回到线程池供其他请求使用。需要注意的是线程池有一个最大容量如果请求数量超过这个容量ASP.NET会采取队列排队的方式对请求进行排队,这个时候我们就会感觉到网页的响应时间边长,就像图书馆里面只有10本书现在来了20个人想要借书那么我们就让多余的人进行排队。
线程池的设计可以给我们带来以下优点
· 线程重用:线程的创建和销毁同样需要占用服务器资源,采用线程池设计避免了频繁的创建和销毁进而提高服务器的吞吐能力(可以有更多的资源用于其他方面)
· 最大数量限制:最大数量限制避免了创建过多线程导致的服务器崩溃现象
如果请求的处理过程很短,线程池内的线程在使用后会被很快的重新放回线程池,这当然是最理想的状态。但如果请求处理过程很长(比如IO处理)那么就会导致线程不能被快速使用完毕后放回至线程池,影响服务器吞吐能力。异步即为了解决这一问题,我们可以在线程池里的线程在使用时如果遇到耗时操作(主要针对IO)为其创建一个后台线程专门处理耗时操作,从而让线程池中的线程可以尽快返还到线程池中提高服务器吞吐能力。
2.异步Action定义
在mvc3的版本中提供了定义异步Action的一种方式,即创建XxxAsync()方法和XxxCompleted()两个方法,XxxCompleted()方法是XxxAsync()方法执行完毕之后的回调方法。ASP.NET并不会以异步的方式执行XxxAsync()方法,而是我们在XxxAsync()方法内自行实现异步。MVC4以后的版本我们可以使用Task完成异步操作。
1 public class HomeController : AsyncController 2 { 3 4 public void IndexAsync() 5 { 6 //异步执行开始标志 7 AsyncManager.OutstandingOperations.Increment(); 8 Task.Factory.StartNew(() => 9 { 10 string path = ControllerContext.HttpContext.Server.MapPath("\\Texts\\围城.txt"); 11 using (StreamReader sr = new StreamReader(path)) 12 { 13 //回调时传递的参数 14 AsyncManager.Parameters["Content"] = sr.ReadToEnd(); 15 } 16 AsyncManager.Parameters["count"] = 1; 17 AsyncManager.Parameters["person"] = new Person { Name = "张三" }; 18 //异步执行结束标志 ① 19 AsyncManager.OutstandingOperations.Decrement(); 20 }); 21 //② 22 23 } 24 25 public ActionResult IndexCompleted(string content, int count,Person person) 26 { 27 return Content(content); 28 } 29 30 } 31 32 public class Person 33 { 34 public string Name { set; get; } 35 }
AsyncController
跟踪执行过程
此种方式操作起来相对比较麻烦。而且一般需要借助于AcynManager对象完成异步操作。
3.AsyncManager
首先我们把代码中标注①的代码放到//②的位置,再跟踪代码会发现IndexCompleted(string content, int count,Person person)方法中的参数有时会被赋值有时为null,
这又是为什么呢?
AsyncManager.OutstandingOperations.Decrement();标志后台线程执行完毕,此时可以开始执行IndexCompleted方法,如果把它放到②位置处则只是通知IndexAsync方法执行完毕,至于Task.Factory.StartNew中的后台任务不一定执行完毕,所以出现上述情况,因此使用此种方式设计一部Action时我们需要注意AsyncManager.OutstandingOperations.Decrement();的位置。
下面我们深入分析一下AsyncManager的原理