在 Asp.net MVC 应用程序中,有时间需要执行一些异步操作。那么 Asp.net MVC 下的异步请求是怎么一个过程呢?  异步被调用时,发生以下过程:

1. Web服务器从线程池得到一个线程(工作线程),接着安排它来处理进来的请求,该工作线程启动一个异步操作。

2. 工作线程被线程池收回,为另一个Web请求服务。

3. 当异步操作完成后,它会通知ASP.NET。

4. Web服务器从线程池获取一个工作线程(这可能是一个不同的开始异步操作的线程)来处理剩余的请求,包括呈现与响应请求。


看下面的模式图:

IC371798Async


接着,我们来看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

posted on 2013-01-07 17:09  PetterLiu  阅读(6077)  评论(0编辑  收藏  举报