WCF實例與並發


WCF中的並發針對服務而言。而服務實例封裝在InstanceContext,所以WCF中的並發最終體現在了InstanceContext中。WCF服務實例上下文模式InstanceContextMode又決定服務以何種方法為客戶端提供服務。

 

實例模式 :

public  enum InstanceContextMode
{
    PerSession,
    PerCall,
    Single
}
PerSession:每次會話都是使用同一個服務實例
PerCall:每次調用都創建新的服務實例對象
Single:所有服務都是用同一個服務實例對象,相當於所有客戶端代理都使用服務端同一個靜態服務實例對象為其服務
默認情況下,InstanceContextMode默認為PerSession

 

並發部分: 

服務通過ServiceBehaviorAttribute的ConcurreceMode屬性定義了三種不同的並發模型:

 

public  enum ConcurrencyMode
{
    Single,
    Reentrant,
    Multiple
}
Single:封裝服務實例的InstanceContext某時刻只處理一個客戶端請求,其他的請求會被放入請求隊列中等待處理。如果多個客戶端對服務並發訪問,這些服務最終在服務端也是通過串行化進行處理。如果之前的請求處理完畢,隊列中的第一個請求會被處理。它的實現是對InstanceContext繼承自CommucationObject中ThisLock
Reentrant:該模式與Single一樣,某時刻只能處理一個客戶端請求。與Single不同的是:如果在處理 請求A時,某時刻服務端回調客戶端,此時服務可繼續處理下一個請求B。當回調客戶端完成返回服務端,如果B請求沒有處理完,則A請求需要繼續等待直至請求B釋放鎖,此時如果A能獲取到鎖,則它的請求被繼續執行。
Multiple:在該模式下,封裝服務實例的一個InstanceContext能同時處理多個請求。
默認情況下,ConcurrencyMode 為Single。
下面測試一下幾種實例與並發模式
服務契約定義:
    [ServiceContract]
     public  interface IAdd
    {
        [OperationContract]
         void Add( int x,  int y);
    }
服務實現:
public  class AddService : IAdd
    {
         private  readonly  int counter =  0;

         public AddService()
        {
            counter++;
            Console.ResetColor();
            Console.WriteLine( string.Format( " AddService Construction function excute... counter is {0} ", counter));
        }

         #region IAdd 成員

         public  void Add( int x,  int y)
        {
             var clientId = OperationContext.Current.IncomingMessageHeaders.GetHeader< int>(MessageWrapper.headerClientId,
                                                                                          MessageWrapper.headerNamespace);
            Console.ForegroundColor = ConsoleColor.Red;
            Console.WriteLine( string.Format( " Time:{0};ThreadId is :{1}.Request Id is {2} Add Method Invoked, ", DateTime.Now,Thread.CurrentThread.ManagedThreadId,clientId));
            Console.WriteLine( string.Format( " result is : {0} ",x + y));
            Thread.Sleep( 5000);
            Console.WriteLine( " =========Excute finished========= ");            
            Console.WriteLine();
        }

         #endregion
    }
服務端配置:
        <system.serviceModel>

<services>
            <service name="Service.AddService">
                <endpoint address="http://127.0.0.1:3636/AddService" binding="basicHttpBinding" contract="Contract.IAdd"></endpoint>
            </service>
        </services>
    </system.serviceModel>

 

客戶端配置這里不再給出。 客戶端調用代碼:

 

ChannelFactory<IAdd> factory= new ChannelFactory<IAdd>( " AddService ");
IAdd proxy = factory.CreateChannel();  

for (int i = 0; i < 5; i++)
{                

ThreadPool.QueueUserWorkItem(delegate
                                    {
                                    int clientId = Interlocked.Increment(ref index);
                                        using (OperationContextScope contextScope =
                                                             new OperationContextScope(proxy as IContextChannel))
                                        {
                                          MessageHeader<int> header = new MessageHeader<int>(clientId);
                                                System.ServiceModel.Channels.MessageHeader messageHeader =
                                                header.GetUntypedHeader(MessageWrapper.headerClientId,
                                                MessageWrapper.headerNamespace);
                                                OperationContext.Current.OutgoingMessageHeaders.Add(messageHeader);
                                                proxy.Add(12);
                                          }
                                       });
 }

 

測試1:PreCall + Multiple:

輸出如下:

 

                                                          圖1 

由以上輸出,服務對客戶端調用是以串行的方式進行的。 以上我們設置的ConcurrencyMode.Muliple。明明是並發模式,為何服務端卻以串行的方式執行呢。?這是因為如果服務代理以自動開啟的方式(即進行調用時,如果代理沒有打開,調用時會打開代理)進行並發調用,WCF需要對調用進行序列化知道代理打開之后在進行並發處理。如果將代理顯示開啟,則就能顯示並發調用結果。對代碼進行如下修改:

IAdd proxy = factory.CreateChannel();  
if ( null != proxy  as ICommunicationObject)
{
    (proxy  as ICommunicationObject).Open();
}
for ()
{
  /**/ }   

服務端輸出如下:

 

                                                            圖2

測試2:PerSession + Single/Reentrant

1、將綁定協議換成支持會話的綁定,如wsHttpBinding,服務端輸出如上圖1
2、將綁定協議換成不支持會話的綁定,如basicHttpBind個ing ,服務端輸出如上圖2
由此可知: PerSession+Single/Reentrant下:Allowed+不支持會話的綁定,此時為服務端並發處理請求。
Allowed  +支持會話的綁定,此時為服務端串行處理請求(SessionMode不進行設置時,默認為Allowed).

測試3: Single + Single

將服務實例模式改為Single,即
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single)]
此時服務端輸出如圖3:

 

                                                          圖3 

由輸出可知: Single+Single/Reentrant下, 服務端串行處理請求

測試4: Single + Multiple

將服務實例模式改為Single,並發模式為Multiple即
[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single,ConcurrencyMode = ConcurrencyMode.Multiple)]
此時服務端輸出如下:
                                                    圖4 

 測試5:PerCall+ Single/Reentrant/Multiple

將服務實例模式改為PerCall,無論並發模式如何,此時中表現為並發。對WCF而言,並發是對實例上下文InstanceContext而言的。無論對於相同客戶端調用(相同服務代理)還是不同客戶端調用請求,WCF客戶端都會重新生成InstanceContext,通過封裝在其中的服務實例進行對調用的處理,因此不會存在對InstanceContext的並發調用.
[ServiceBehavior(InstanceContextMode=InstanceContextMode.PerCall)]
此時總為並發:此時服務端輸出如下:

                                                           圖5

 

由以上分析對於不同實例模式,以及並發模式總結如下圖:  

 


 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2026 CODEPRJ.COM