在 Asp.net MVC 应用程序中,有时间需要执行一些异步操作。那么 Asp.net MVC 下的异步请求是怎么一个过程呢? 异步被调用时,发生以下过程:
1. Web服务器从线程池得到一个线程(工作线程),接着安排它来处理进来的请求,该工作线程启动一个异步操作。
2. 工作线程被线程池收回,为另一个Web请求服务。
3. 当异步操作完成后,它会通知ASP.NET。
4. Web服务器从线程池获取一个工作线程(这可能是一个不同的开始异步操作的线程)来处理剩余的请求,包括呈现与响应请求。
看下面的模式图:
接着,我们来看Controller的代码:
1: public class HomeController : AsyncController
2: {
3: public void IndexAsync()
4: {
5: AsyncManager.OutstandingOperations.Increment(2);
6:
7: Task.Factory.StartNew(() =>
8: {
9: // Perform some expensive operation
10: string uri = "http://www.cnblogs.com";
11:
12: WebClient client = new WebClient();
13: string reply = client.DownloadString(uri);
14:
15: AsyncManager.Parameters["data"] = reply;
16: AsyncManager.OutstandingOperations.Decrement();
17: });
18: Task.Factory.StartNew(() =>
19: {
20: // Perform another expensive operation
21: string uri = "http://www.cnblogs.com/wintersun/";
22:
23: WebClient client = new WebClient();
24: string reply = client.DownloadString(uri);
25:
26: AsyncManager.Parameters["moredata"] = reply;
27: AsyncManager.OutstandingOperations.Decrement();
28: });
29: }
30:
31: public ActionResult IndexCompleted(string data, string moredata)
32: {
33: Operations translations = new Operations { FirstOperation = data, SecondOperation = moredata };
34:
35: return View(translations);
36: }
37:
38: }
我们看到上面的代码让Controller继承自AsyncController,那个叫IndexAsync的action对应是Index的View。中间的代码使用Task Parallel library(TPL)来模拟下载网页内容,最后在完成后又通过AsyncManager.Parameters字典传值给IndexCompleted的Action, 有注意Key的名称moredata与IndexCompleted Action的参数名moredata相同。AsyncManager下的Parameters字典用于转递一组参数值到最后异步调用的方法。 AsyncManager下有一个管理异步操作的计数器,应当务必确保执行异步操作后,执行Decrement方法,甚至异步操作失败,当所有线程完成时这个计数器的值必须为0。 当异步调用我们让View返回:
1: <%@ Page Language="C#" Inherits="System.Web.Mvc.ViewPage<AsyncProject.Models.Operations>" %>
2: <!DOCTYPE html>
3: <html>
4: <head runat="server">
5: <title>Translate Completed</title>
6: </head>
7: <body>
8: <div>
9: The controller has completed.
10: </div>
11: </body>
12: </html>
使用到一个简单Model:
public class Operations
{
public string FirstOperation { get; set; }
public string SecondOperation { get; set; }
}
好了,那么什么时候用异步,什么用同步呢?
当这些条件满足的情况下,可以考虑使用异步:
1. 密集地操作的网络或I/O,而不是CPU密集运算的。
2. 测试结果表明阻塞操作是网站的性能瓶颈,为了让IIS服务器可以处理更多的请求,在处理这些阻塞调用时使用异步Action方法。
3. 并行化比简单代码更重要。
4. 需要提供一种机制,允许用户取消一个长期运行任务的请求。
实际开发,你需要测试是否异步操作可以提高性能。同时,在某些情况下可能话,增加IIS每个CPU配置最大并发请求处理和最大并发线程。
关于Asp.net 服务器线程配置看这篇文章:ASP.NET Thread Usage on IIS 7.5, IIS 7.0, and IIS 6.0
关于是否需要数据库异步调用看这里: Should my database calls be Asynchronous
我们介绍到这儿,有兴趣可以自己尝试一下,后面有时间将介绍Asp.net MVC 4 与 .net framework 4.5 的异步操作。
作者:Petter Liu
出处:http://www.cnblogs.com/wintersun/
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
该文章也同时发布在我的独立博客中-Petter Liu Blog。