程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> .NET網頁編程 >> 關於.NET >> WCF從理論到實踐(11)-異步

WCF從理論到實踐(11)-異步

編輯:關於.NET

本文目的

通過閱讀本文,您能了解以下知識

1) 如何在WCF中實現異步

2) 異步操作的優缺點及其應用場合

3) 總結對比各種異步操作的實現方式

4) 代碼不騙人,實現一個WCF異步小范例

本文適合的讀者

本文因為涉及一些常用的基礎知識和開發技巧,需要對多線程等具有一定的認識,所以初學者可能不能立即掌握,本文適合WCF中級用戶或有其他分布式技術開發經驗的WCF初學者

如何在WCF中實現異步

在ARM(異步編程模型)中,我們經常看到BeingXXX(..),EndXXX(..)這樣的函數定義,那和他們對應的同步方法還有XXX(..),比如FileStream對象,它既包括同步方式int Read(byte[] buffer,int offset,int count),還有IAsyState BeginRead(byte[] buffer,int offset,int count,IAsyCallback callback,Object asyState)和int EndRead(IAsyState ar)這樣的異步方式,如果我們的WCF服務程序也和FileStream設計一樣,那我們一些開發人員要跳樓了.本來一個業務方法的實現現在變為了3個,工作量增加了2倍.為何有這樣的說法,因為這樣的架構不是一個好架構,作為一個優秀的框架,WCF肯定不會犯如此低級的錯誤,異步與否本來應該是由客戶端來決定的,所以我們的服務端實現無需關心異步與否.下面我們來看一下如何實現異步,WCF中實現異步是一件非常簡單的事情,我們用svcutil來生成客戶端代理代碼的時候,只需添加 /async便可以生成有異步功能的代理類了.而在IDE中,操作就更加簡單,就是在添加ServiceReference的時候,選擇高級選項,鉤選Generate Asynchronus operations,如圖:

生成異步操作的代理類下就會增加BeginXXX和EndXXX方法。比如我們示例項目中服務契約中有

[OperationContract]
string GetData(int value);

的操作方法,生成的代理類中對應其的異步方法為:

[System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action="http://tempuri.org/IService1/GetData", ReplyAction="http://tempuri.org/IService1/GetDataResponse")]
System.IAsyncResult BeginGetData(int value, System.AsyncCallback callback, object asyncState);
string EndGetData(System.IAsyncResult result);

異步操作的優缺點及其應用場合

在前面WCF從理論到實踐:事件廣播文章中,我曾經提到異步操作能提高系統的吞吐能力,老趙同志也曾針對我的說法寫了篇正確使用異步操作來校正濫用異步的錯誤做法,那異步究竟有何優點值得我們使用?而又有什麼缺點需要我們使用的時候小心呢?誠如老趙所說,異步並不一定能提高系統性能,甚至因為線程的創建,消亡,和切換會增加系統開銷,但異步除了提高性能,還可以增強系統的健壯性。在過去,windows程序總是單線程的,在這樣的系統中,如果出現了異常,系統就會 因此而崩潰,甚至連我們的操作系統也是單線程的,所以每次出現異常,我們的計算機用戶都要不厭其煩強制關機,然後重啟才能解決問題。加入多線程之後,當一個線程上的任務發生異常的時候,其他線程有能力不受影響,從此防止整個應用程序的崩潰。此外如果用戶是在一個UI中操作某項耗時的操作,如果不使用異步,那UI線程就會被阻塞,導致界面無法響應,用戶就會很無助,增加了異步,讓復雜的任務在另外的線程中完成,就會有比較好的用戶體驗。而且異步並不是說對性能提高沒有作用,CLR線程的創建,銷毀,和線程上下文切換的確會有很大的開銷,比如每創建一個線程,都必須申請1MB的地址空間用於線程的用戶模式,申請12KB左右的德地址空間用於線程的內核模式,而且還要求進程調用每個dll中的一個 固定的函數來通知所有的dll系統創建了一個新的線程,同樣在銷毀的時候,也要做類似的通知,上面這一切似乎都說明了異步操作對於性能的壞處,但事實並非完全如此,我們知道當前的處理器基本上都是雙核,或者支持hyper-thread,一個線程的執行總會占用1個cpu邏輯核,如果我們的計算機是4核,8核,而我們不采用異步,那其實多核就沒什麼太大優勢,因為總是1個核在工作,而另外的核卻在休息,效率肯定低下,而此時用多線程,就可以充分使用計算機的處理器資源。同時對於一些有IO限制的操作而言,如讀取磁盤文件,網絡數據相關操作時,整個過程並不是完全靠運算,而是要通過磁盤驅動器或者網絡驅動器來協助完成,比如讀取磁盤中的一個文件,當應用程序的讀取線程發出讀請求的時候,該請求會被磁盤驅動器所排隊處理,假如它是個很長的操作,那麼該操作會在磁盤驅動器上排隊或者執行很長時間,而這段時間讀線程就處於阻塞的狀態,這樣就浪費了線程資源,正確的做法應該是線程將讀請求發送到磁盤驅動器後馬上返回,繼續處理其他任務,而當磁盤驅動器操作完成的時候,由磁盤驅動器來通知或者由一個線程來輪詢執行狀態。這樣就防止線程資源被浪費,從而提高系統性能。總結一下上面的說法,異步有三個優點:

1) 在I/O受限等情況下,異步能提高性能,並且能更加充分利用多核CPU的優點。

2) 異步能增強系統健壯性

3) 異步能改善用戶體驗

同時也有缺點,如下

1) 濫用異步,會影響性能

2) 增加編程難度

總結對比各種異步操作的實現方式

實現異步,主要包含以下幾種方法

1) 使用專用線程,方法為:

System.Threading.ThreadStart ts = new System.Threading.ThreadStart(void(object state) target);

System.Threading.Thread th = new System.Threading.Thread(ts);

ts.Start();

調用Start()方法之前,並沒有實質性得創建線程資源,而是Start()後才進行創建,此種方式的好處在於能設置線程是前台線程還是後台線程,並且能控制線程的掛起和消亡

2) 使用線程池中的線程

線程是一種比較寶貴的資源,所以使用的時候就要加倍珍惜,線程池中線程在使用完成之後並不是馬上銷毀,而是回到池中等待下一次的使用,這樣就可以較少線程創建的消耗。使用方法如下:

ThreadPool.QueueUserWorkItem(WaitCallback callback)

需要注意的是此種方法使用的均為後台線程 

3) 使用異步編程模型

這種方法是MS推薦的使用方法,該模型普遍格式為:

BeginXXX(…IAsyCallBack callback,object asyState);

EndXXX(IAsyState ar);

這種模型的好處上面已經有所闡述

4) 使用BackgroundWorker

.Net2.0下提供了BackgroundWorker,使用它可以輕易的完成異步操作,並且它還有一些功能上的加強,比如取消操作、

代碼不騙人,實現一個WCF異步小范例

非常簡單,並不多說,只發項目文件和運行效果圖:

本文配套源碼

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved