WCF中的AsyncPattern

WCF中的AsyncPattern

 

(系列博文源自 http://pfelix.wordpress.com/,由笔者翻译并整理,转载请注明)

在wcf 的 service contract中, 服务接口方法定义都要求有 operation context这个标签。 在这个标签里有一个 AsyncPattern的属性用以定制 service的异步模型。

考虑如下接口定义:

复制代码
1: [ServiceContract]   
2: interface IService {   
3:     [OperationContract]   
4:     ReplyData Operation1(RequestData rd);   
5:    
6:     [OperationContract(AsyncPattern = true)]   
7:     IAsyncResult BeginOperation2(RequestData rd, AsyncCallback ac, object obj);   
8:     ReplyData EndOperation2(IAsyncResult ar);   
9: }
复制代码
  • 第一个服务方法定义中, AsyncPattern默认为false。 这是一个简单的 request-response方法 'Operation1'. 在默认设置下,这个方法由server端同步实现。 具体过程是由 WCF Dispatcher调用这个方法,生成传入参数,在这个方法执行过程中会占用这个service线程,最终返回reply,并由wcf生成返回消息传回客户端。
  • 第二个服务方法定义中, AsyncPattern设成true,同样定义了一个request-response方法 'Operation2'。然而, 这个方法实现要求是一个包含两个方法:BeginOperation2, EndOperation2的异步实现。在这里的‘异步’ 意味着
    • WCF dispatcher 调用 BeginOperation2 , 生成传入参数和一个异步回调, 还有一些状态信息。
    • 这个方法开始执行并最终返回一个IAsyncResult
    • 当这个方法执行结束时会调用AsyncCallback 。
    • 这个AsyncCallback 是由wcf实现 会接下来调用 EndOperation2 收集返回值并把消息传回给客户端。     

需要注意的是,即使设置了AsyncPattern, 在通信层面而言这个service依然是一个 request-response 模型。 这个异步只是service 的实现细节。 参考生成的wsdl定义:  

复制代码
1: <wsdl:portType name="IService">   
2:     
3:   <wsdl:operation name="Operation1">   
4:     <wsdl:input wsaw:Action="..." message="..." />    
5:     <wsdl:output wsaw:Action="..." message="..." />    
6:   </wsdl:operation>   
7:     
8:   <wsdl:operation name="Operation2">   
9:     <wsdl:input wsaw:Action="..." message="..." />   
10:     <wsdl:output wsaw:Action="..." message="..." />   
11:   </wsdl:operation>  
12:    
13: </wsdl:portType>
复制代码

这并不会改变service的通信模型,有别于普遍意义上的 “异步服务”。

那么,这种实现方式有什么意义? 或者说在何种场景下应该使用这种实现方式?

砖家说,当服务实现中会长时间block住当前服务线程时就应该考虑这种实现方式。

结合上图应该能比较容易理解这种方式带来的优势, 在上图的例子中这种实现方式能在开始 io前释放服务线程, 并在 io结束后重新获得一个线程做后续操作。

理论上来说这种方式就不会存在一个‘被阻塞’的线程,以节约线程资源来提升service并发。

最后提一下在client端这个属性的作用。

当使用 svcutil.exe时加上 /async 会生成以下服务器代理接口定义:

复制代码
1: public interface IService {   
2:        
3:     // Operation 1 synchronous method      
4:     [System.ServiceModel.OperationContractAttribute(Action=".../Operation1", ReplyAction=".../Operation1Response")]   
5:     ReplyData Operation1(RequestData rd);   
6:     
7:     // Operation 1 asynchronous method pair            
8:     [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action=".../Operation1", ReplyAction=".../Operation1Response")]   
9:     System.IAsyncResult BeginOperation1(RequestData rd, System.AsyncCallback callback, object asyncState);          
10:     ReplyData EndOperation1(System.IAsyncResult result);  11:           
12:     // Operation 2 synchronous method     
13:     [System.ServiceModel.OperationContractAttribute(Action=".../Operation2", ReplyAction=".../Operation2Response")]  
14:     ReplyData Operation2(AsyncPattern.Client.AsyncClient.RequestData rd);
15:           
16:     // Operation 2 asynchronous method pair           
17:     [System.ServiceModel.OperationContractAttribute(AsyncPattern=true, Action=".../Operation2", ReplyAction=".../Operation2Response")] 
 18:     System.IAsyncResult BeginOperation2(RequestData rd, System.AsyncCallback callback, object asyncState);          
19:     ReplyData EndOperation2(System.IAsyncResult result);  20:       
21: }
复制代码

如果理解了一开始的部分,很容易想到这根服务器端的实现方式无关。 这只是客户端的一种内部实现方式。

其效果就是调用服务器时会立刻返回(而不阻塞),再由调用EndOperation的形式得到执行结果。

值得一提的是类似的效果虽然可以通过多线程来实现。 但依然不会有wcf Async机制高效, 因为wcf 的异步模型是基于通信层支持, 并不会阻塞任何一个线程。而多线程实现依然会阻塞线程池中的异步线程。

(译者:多数情况而言在客户端这点优势倒没啥意义。。。。)

原文地址:https://www.cnblogs.com/raohuagang/p/3553570.html