<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      async 與 await 在 Web 下的應用

      原文地址:http://www.dozer.cc/2012/03/async-and-await-in-web-application/

      歡迎大家到我的博客中查看,排版會更舒服一點!

       

      .net 中的異步

      關于 .net 的異步,一篇文章是講不完的,我這里就貼兩篇文章讓大家看一下:

      《正確使用異步操作》、《C#客戶端的異步操作》、《細說ASP.NET的各種異步操作》

      另外,在 .net 4.0 中還推出了新的任務并行庫(TPL),也是一種新異步模式:

      《任務并行庫》

      最后,.net 4.5 又推出了全新的 async 和 await 關鍵字:

      《C#與Visual Basic的未來(上)》

      《C#與Visual Basic的未來(中)》

      《C#與Visual Basic的未來(下)》 

      最后,在這幾篇文章的基礎上,想和大家談談 async 和 await 在 Web 下的應用,包括 WebForm 和 MVC

       

      async 與 await 的簡單介紹

      仔細看完老趙的《C#與Visual Basic的未來》大家應該都能明白這兩個關鍵字的作用是什么了。

       

      適用條件:只能適用于TPL異步模式

      傳統的方法返回的就是需要返回的內容,而基于TPL模式的異步,返回的都是 Task<T>,其中的 T 類型就是你需要返回內容的類型。

      在 Visual Studio 11 中,只要你調用的某個方法返回的類型是 Task 或者 Task<T>,它就會提示這是一個可等待的方法。

      這時候,就可以利用 async 和 await 關鍵字了。

       

      場景:解決基于事件的異步中回調函數嵌套使用中的問題

      假設有這樣一個場景,一個 C# 應用程序中(WinForm Or WPF)我需要從一個網站上下載一個內容,然后再根據內容里的網址再下載里面的內容。

      如果直接利用 WebClient 的 DownloadString 方法,很明顯 UI 線程會被阻塞,沒人會這么做。

      如果只是一次下載,那利用 WebClient 的 DownloadStringAsync 就可以輕松解決了,但是如果是想這樣需要兩次下載,而且兩次下載是有關聯的呢?如果是三次四次呢?

      我們先來看看用基于事件的異步來實現:

      protected void DownloadAsync()
      {
          WebClient client = new WebClient();
          client.DownloadStringCompleted += client_DownloadStringCompleted;
          client.DownloadStringAsync(new Uri("http://www.website.com"));
      }
      void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
      {
          WebClient client = new WebClient();
          client.DownloadStringCompleted+=client_DownloadStringCompleted2;
          client.DownloadStringAsync(new Uri(e.Result));
      }
      void client_DownloadStringCompleted2(object sender, DownloadStringCompletedEventArgs e)
      {
          var result = e.Result;//最終結果
          //do more
      }

      下面再來看看用 async 和 await 來實現:

      protected async void DownloadTaskAsync() {
          WebClient client = new WebClient();
          var result1 = await client.DownloadStringTaskAsync("http://www.website.com");
          WebClient client2 = new WebClient();
          var result2 = await client.DownloadStringTaskAsync(result1);
          //do more
      }

      是不是簡單多了?

       

      在 WebForm 和 MVC 中使用 async 和 await

      在 .net 4.5 中,最新的 WebForm 和 MVC 都已經支持這兩個關鍵字了。

      在 asp.net WebForm 中:

      1. 首先新建一個頁面
      2. 打開 aspx 文件,然后再頂部的屬性中加入:Async="true"
      3. 接下來在任何一個事件中,加入這兩個關鍵字即可
      4. 另外在 Web.Config 中有兩個奇怪的配置,有可能會導致出錯,去掉有正常,這兩個配置具體有什么用,我已經在 StackOverFlow 上問別人了
      protected async void Page_Load(object sender, EventArgs e)
      {
          WebClient client = new WebClient();
          var result1 = await client.DownloadStringTaskAsync("http://www.website.com");
          WebClient client2 = new WebClient();
          var result2 = await client.DownloadStringTaskAsync(result1);
          //do more
      }

      在 asp.net MVC 中:

      把原來繼承于 Controller 改成繼承于 AsyncController

      在方法前加上 async,并把返回類型改成 Task<T>

      public class HomeController : AsyncController
      {
          public async Task<ActionResult> Test()
          {
              var result = await Task.Run(() =>
              {
                  Thread.Sleep(5000);
                  return "hello";
              });
              return Content(result);
          }
      }

       在 IHttpHandlder 中:

      微軟官方的 .net 4.5 releace note 中已經提到了:

      public class MyAsyncHandler : HttpTaskAsyncHandler
      {
          // ...
      
          // ASP.NET automatically takes care of integrating the Task based override
          // with the ASP.NET pipeline.
          public override async Task ProcessRequestAsync(HttpContext context)
          {
              WebClient wc = new WebClient();
              var result = await
                  wc.DownloadStringTaskAsync("http://www.microsoft.com");
              // Do something with the result
          }
      }

       在 IHttpModule 中:

      同樣是微軟官方的 .net 4.5 releace note 中,實現起來有點復雜,大家可以自己去看看。

       

      在 Web 應用程序中使用 async 和 await 的注意事項

      其實不僅僅是使用這兩個關鍵字的注意事項,而是在 Web 中只要用到了異步頁,就要注意一下問題!

      Web 本來就是多線程的,為什么還要用異步編程?

      多線程只是實現異步的一種手段,的確,Web 本來就是多線程的,所以在很多時候不用異步也沒什么問題。一般也不會有問題,只是有更好的方案。

      大家看完《正確使用異步操作》后就會知道,異步有多種實現方式,但是它們底層只有兩種類型,一種是:“Compute-Bound Operation”,另一種是“IO-Bound Operation”。(具體的可以到文中查看)

      在 Web 中,使用異步去處理“Compute-Bound Operation”是沒有意義的,因為 Web 本來就是多線程的,這樣做沒有任何效率上的提升。(除非你在處理這個異步的時候,不需要等待這個異步執行結束就可以返回頁面內容)

      所以,在 Web 中,只有當你需要面對“IO-Bound Operation”的時候,去用異步頁才是真的有用的。因為它是在等待磁盤或者網絡響應,并不占據資源,甚至不占據工作線程。

      如何區分呢?那篇文章中已經寫了,另外,大部分和磁盤&網絡打交道的異步操作都是“IO-Bound Operation”的。

      但是,如果你真的想要提升效率,還需要你親自去測試一下,因為要實現“IO-Bound Operation”有一定的條件。

      WebClient、WebService 和 WCF 支持嗎?

      經過測試,上面這三種 Web 應用程序中使用最多的,是支持“IO-Bound Operation”的。其中,在 .net 4.5 中,WebClient 和 WCF 可以直接支持 async 和 await 關鍵字。(因為它們有相關的方法可以返回 Task 對象)

      而 WebService(微軟不建議使用,但實際上還在被大量的應用),卻不支持,但是可以通過寫一些代碼后讓它支持。

      數據庫操作支持嗎?

      經過一定的配置后,它是可以支持的,但是具體的還需要進行大量的測試,畢竟不是調用幾個方法那么簡單。

       

      如何把傳統的異步模式轉換成 TPL 模式,以實現 async 和 await

      上面提到了 WebService 并沒有實現 TPL 模式,在 .net 4.5 中引用 WebService 后實現的是基于事件的異步。

      (.net 2.0 以上程序在引用 WebService 的時候,需要點“添加服務引用”——“高級”——“添加Web引用”,如果直接在服務引用中添加,會出現一定的問題。并且,就算你添加了,它也沒有幫你實現基于 TPL 的異步。)

      如何把 APM 模式轉換成 TPL 模式?

      其實微軟在這篇文章中已經寫過如何把傳統的異步模式轉換成 TPL 模式了:TPL 和傳統 .NET 異步編程

      其中 APM 轉 TPL 比較簡單,我就不多介紹了。

       

      如何把 EAP 模式轉換成 TPL 模式?

      EAP 就是基于事件的異步,上面那篇文章中其實也提到了,但是寫的并不是很清楚。

      下面我用一段簡化的代碼來實現 EAP 轉 TPL:

      namespace WebServiceAdapter.MyWebService
      {
          public partial class WebService
          {
              /// <summary>
              /// 無 CancellationToken 的調用
              /// </summary>
              /// <returns></returns>
              public Task<string> HelloWorldTaskSync()
              {
                  return HelloWorldTaskSync(new CancellationToken());
              }
      
              /// <summary>
              /// 有 CancellationToken 的調用
              /// </summary>
              /// <param name="token"></param>
              /// <returns></returns>
              public Task<string> HelloWorldTaskSync(CancellationToken token)
              {
                  TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
      
                  token.Register(() =>
                  {
                      //注冊 CancellationToken
                      this.CancelAsync(null);
                  });
      
                  //注冊完成事件
                  this.HelloWorldCompleted += (object sender, HelloWorldCompletedEventArgs args) =>
                  {
                      if (args.Cancelled == true)
                      {
                          tcs.TrySetCanceled();
                          return;
                      }
                      else if (args.Error != null)
                      {
                          tcs.TrySetException(args.Error);
                          return;
                      }
                      else
                      {
                          tcs.TrySetResult(args.Result);
                      }
                  };
      
                  //異步調用
                  this.HelloWorldAsync();
      
                  //返回 Task
                  return tcs.Task;
              }
          }
      }

      轉換好后再去配合使用 async 和 await 關鍵字就方便多了:

      protected async void Page_Load(object sender, EventArgs e)
      {
          using (WebService service = new WebService())
          {
              await service.HelloWorldTaskSync();
          }
      }

       

      性能測試

      前期準備:

      理論和實際代碼都講完了,是不是該拿出點東西來驗證一下了?

      在做性能測試的時候我繞了很多彎路,碰到了很多問題,一度讓我懷疑它是不是真的可以提升性能。

      但最終還是解決了!感謝老趙的一篇文章:體會ASP.NET異步處理請求的效果

       

      異步頁最大的用處就是在處理“IO-Bound Operation”的時候可以不占據工作線程。

      測試的理論:

      • 限制網站應用程序的工作線程,然后同時請求一個頁面,請求數大于工作線程數。
      • 請求的頁面會訪問一個 WebService ,這個 WebService 會延遲5秒,對于網站來說,這個5秒就是“IO-Bound Operation”。
      • 如果限制了工作線程數后,異步頁所有請求都可以在5秒完成,那說明的確沒有占據工作線程。反之則說明理論錯誤!

       

      我一開始限制的工作線程是10,然后同時請求50,但是無論是異步頁還是同步頁,總耗時都差不多…

      后來仔細看老趙的文章才發現,原來在 Vista & Win7 中最大請求數被限制在10了,所以多于10的請求根本沒到達網站應用程序。

      最后我把工作線程限制在2,然后同時請求10,終于得到了正確的理論數據!

       

      工具準備:

      我這里用的工具是 apache 下那只的 ab.exe,簡單好用!

      另外我也寫了相關的代碼來支持測試。

       

      開始測試:

      運行 WebService,提供一個會延時5秒的服務。

      然后運行網站,有三個頁面:

      • NoAsyncPage.aspx :傳統的頁面
      • AsyncPage_IO.aspx:異步頁面,和傳統頁面一樣,都是調用 WebService ,但是是用異步調用
      • AsyncPage_CPU.aspx:為了驗證在異步中執行“Compute-Bound Operation”是沒有意義的

       

      在CMD中,依次用 ab.exe 調用這三個頁面:

      ab -c 10 -n 10 http://localhost:6360/noasyncpage.aspx
      ab -c 10 -n 10 http://localhost:6360/asyncpage_io.aspx
      ab -c 10 -n 10 http://localhost:6360/asyncpage_cpu.aspx

       

      最終運行結果如下:

      • NoAsyncPage.aspx :26.39秒
      • AsyncPage_IO.aspx:5.29秒
      • AsyncPage_CPU.aspx:26.54秒

       

      數據分析:

      仔細分析下數據,會發現都符合理論:

      • NoAsyncPage.aspx :沒有采用異步,2個工作線程,10個請求,總事件在10*5/2=25左右。
      • AsyncPage_IO.aspx:采用異步頁,不占據工作線程,10個請求同時執行。
      • AsyncPage_CPU.aspx:雖然采用了異步頁,但是異步的時候依然占據了一個工作線程,而且還多了一些新建線程,切換線程的損耗。

       

      最終結果非常讓人滿意,特別是AsyncPage_IO.aspx,如果我們把訪問量大,并且需要等在磁盤或者是網絡的頁面都改寫成這樣,那可以大大減少IIS管線的消耗!

       

      源代碼和工具下載

      AsyncSample

      請用 Visual Studio 11 打開

      posted @ 2012-03-06 19:39  Dozer  閱讀(6242)  評論(6)    收藏  舉報
      主站蜘蛛池模板: 亚洲免费观看视频| 伊人久久大香线蕉AV网禁呦| 色狠狠综合天天综合综合| 阜宁县| 色爱区综合激情五月激情| 高清一区二区三区不卡视频| 久久久久亚洲AV成人片一区| 久久精品国产再热青青青| 亚洲国产av久久久| 99中文字幕国产精品| 98精品全国免费观看视频| 国产精品亚洲综合久久小说| 国产熟女老阿姨毛片看爽爽 | 日韩大尺度一区二区三区| 亚洲欧美日韩国产四季一区二区三区| 亚洲成在人线在线播放无码| 久久夜色撩人国产综合av| 久久一区二区中文字幕| 国产无遮挡又黄又爽高潮| 亚洲av第一区二区三区| 国产又色又爽又黄的在线观看| 日韩一区二区三区无码影院| 亚洲人成自拍网站在线观看| 动漫av网站免费观看| 熟妇人妻系列aⅴ无码专区友真希| 国语对白刺激在线视频国产网红| 色猫咪av在线网址| 东方四虎在线观看av| 久久久久成人精品无码中文字幕| 国产成人精品亚洲日本语言| 国产精品美女久久久久久麻豆| 国产成人免费午夜在线观看| 色狠狠色噜噜AV一区| 朝阳区| 欧美激情内射喷水高潮| 久久五月丁香激情综合| 谢通门县| 欧美videosdesexo吹潮| 99热精品毛片全部国产无缓冲| 卢湾区| 国产又色又爽又黄的|