好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

WCF实例与并发

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( 1 ,  2 );
                                          }
                                       });
 }

 

测试1:PreCall + Multiple:

输出如下:

 

                                                          图1 

由以上输出,服务对客户端调用是以串行的方式进行的。 以上我们设置的ConcurrencyMode.Muliple。明明是并发模式,为何服务端却以串行的方式执行呢。?这是因为如果服务代理以自动开启的方式(即进行调用时,如果代理没有打开,调用时会打开代理)进行并发调用,WCF需要对调用进行序列化知道代理打开之后在进行并发处理。如果将代理显示开启,则就能显示并发调用结果。对代码进行如下修改:

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

服务端输出如下:

 

测试2:PerSession + Single/Reentrant

由此可知: 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)]

此时总为并发:此时服务端输出如下:

由以上分析对于不同实例模式,以及并发模式总结如下图:  

 

分类:  WCF基础

作者: Leo_wl

    

出处: http://www.cnblogs.com/Leo_wl/

    

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

版权信息

查看更多关于WCF实例与并发的详细内容...

  阅读:42次