【WCF】服务并发中的“可重入模式”
WCF服务实例的并发模式是在服务实现类上,使用 ServiceBehaviorAttribute 的 ConcurrencyMode 属性来指定。其值由 ConcurrencyMode 枚举来界定,这个枚举只有三个值:
Single——服务实例只在单个线程上运行,如果服务是单个实例,那么同一时间只有一个传入的调用被接收,其他调用请拿票排队。
Multiple——这个好理解,服务实例支持多个线程同时调用,所以状态数据可能会不同步(单个服务实例),如果某些变量担心被其他线程意外修改,可以适合地 lock 一下。
Reentrant——这家伙是今天的主角,因为它不太好理解。老周就不抄MSDN了,就按我自己的理解说一下。“可重入模式”大致是这个意思:首先,服务实例是单线程,但是,如果在服务中调用另外的服务,那么此时其他正在排队的传入消息就可以进来。等其他另一个服务调用完成后,又重新进入当前服务操作继续向下执行。有点像你去营业厅排队办业务,服务窗口中的工作人员就是服务实例,而窗口外面排队的客户就是等待调用的客户端。假如我要申请一个业务,通常要填个XXX表格。要是等你填完,估计后面排队的人会跑掉一半。所以,常规的做法是:你站到一边去填表(相当于在服务实例中调用另外一个服务),然后让后面排队的人继续办业务。等你填完表了,再回来找工作人员处理(相当于另外一个服务调用完成,重新进入当前服务实例)。
没看懂?还是实例好用吧。来,下面咱们来动动手吧。
首先我们弄个“另一个”服务。
[ServiceContract]
public interface ISome
{
[OperationContract]
Guid GetUID();
} class SomeService : ISome
{
public Guid GetUID()
{
Guid id = Guid.NewGuid();
Console.WriteLine($"第二个服务被调用,产生的ID为:{id}");
return id;
}
}
这个服务协定有一个方法,作用很简单,产生一个GUID,然后返回,能看懂吧。
好,现在来弄“主”服务。
[ServiceContract]
public interface ITestService
{
[OperationContract]
void TestCall();
}
待会儿我们实现这个协定时,在服务操作方法中去调用前面的“另一个”服务。
internal class TestService : ITestService
{
public void TestCall()
{
Console.WriteLine("即将调用另一个服务。");
// 调用其他服务
ISome cnl = ChannelFactory<ISome>.CreateChannel(new BasicHttpBinding(), new EndpointAddress("http://localhost:12345"));
// 调用完成后,再次回来
Guid id = cnl.GetUID();
((IClientChannel)cnl).Close();
Console.WriteLine($"回到当前服务。得到的ID为:{id}");
}
}
还没完呢,我们设置一下这个服务类,让它使用“可重入”并发模式。
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall, ConcurrencyMode = ConcurrencyMode.Reentrant)]
internal class TestService : ITestService
{
……
}
启动ServiceHost并接收请求。
using (ServiceHost host = new ServiceHost(typeof(TestService)))
{
host.AddServiceEndpoint(typeof(ITestService), new WSHttpBinding(), "http://localhost:9000");
host.Open(); //运行服务
Console.WriteLine("主服务已启动。");
……
Console.ReadKey();
}
模拟客户端调用,咱们开N个 Task 来模拟同时有 N 个客户端调用服务的情形。
Action actdlg = () =>
{
ITestService cn = ChannelFactory<ITestService>.CreateChannel(new WSHttpBinding(), new EndpointAddress("http://localhost:9000"));
cn.TestCall();
// 关闭通道
((IClientChannel)cn).Close();
};
// 开启5个任务
Task[] tasks = new Task[];
// 初始化每个任务
for (int n = ; n < tasks.Length; n++)
{
tasks[n] = new Task(actdlg);
}
// 开始执行任务
foreach (Task t in tasks)
{
t.Start();
}
// 等待所有任务完成
Task.WaitAll(tasks);
最后的 Task.WaitAll 用以等待所有 Task 完成执行,此处可以不要这句。
好,见证的时刻即将来了。运行!

在当前服务去调用另外一个服务的时候,其他正在等待的调用就会进来,在上图中,上面的是“另一个”服务被调用时生成的 GUID,下面是“另一个”服务调用完成后返回到当前服务后得到的 GUID。
从图中,大家会发现,“另一个”服务产生ID输出的顺序,与调用返回后输出的顺序不同,看来,调用完成后,重新进入到当前服务实例的消息还得排队,故调用后返回的消息顺序与“另一个”服务生成ID的顺序并不一致。
不知道用这个示例来装逼之后,各位是否能理解“可重入”并发的含义。
【WCF】服务并发中的“可重入模式”的更多相关文章
- java并发系列(三)-----ReentrantLock(重入锁)功能详解和应用演示
1. ReentrantLock简介 jdk中独占锁的实现除了使用关键字synchronized外,还可以使用ReentrantLock.虽然在性能上ReentrantLock和synchronize ...
- SQL Server存储过程中防止线程重入处理方式
对于线程重入,在C#中有lock关键字锁住一个SyncObject,而SQL Server也可用一个表来模拟实现. 先创建一个同步表,相当于C#中的SyncObject,并插入一条记录(初始值为1) ...
- c中的可重入和不可重入函数
可重入和不可重入 的基本概念 ---简介--- 可重入函数主要用于多任务环境中,一个可重入的函数简单来说就是可以被中断的函数,也就是说,可以在这个函数执行的任何时刻中断它,转入OS调度下去执行另外一段 ...
- 23、Java并发性和多线程-重入锁死
以下内容转自http://ifeve.com/reentrance-lockout/: 重入锁死与死锁和嵌套管程锁死非常相似.锁和读写锁两篇文章中都有涉及到重入锁死的问题. 当一个线程重新获取锁,读写 ...
- WCF服务编程中使用SvcMap实现类型共享等技巧【转】
原文链接:http://www.cr173.com/html/19026_1.html 国外的一篇文章:Sharing DataContracts between WCF Services 文中提到的 ...
- WCF服务创建与使用(请求应答模式)
不说废话,直接上代码.以下服务创建是在独立的WCF类库中,若采用WCF应程程序,定义及创建服务代码均相同,但文件名不同,是CalculatorService.svc 第一步,定义服务契约(Servic ...
- C# 用SoapUI调试WCF服务接口(WCF中包含用户名密码的验证)
问题描述: 一般调试wcf程序可以直接建一个单元测试,直接调接口. 但是,这次,我还要测试在接口内的代码中看接收到的用户名密码是否正确,所以,单一的直接调用接口方法行不通, 然后就想办法通过soapU ...
- 创建寄宿在Windows服务中的WCF服务
1.创建Windows服务项目 2.Server1改名为你想要的名称,比如WinServer 3.在项目中新建一个WCF文件夹,用于存放wcf服务文件. 注:在WcfServer类的上面还要添加 [S ...
- WCF之并发,吞吐量和限流
并发 Single重入模式.对于每一个服务实例,同一时刻只能处理一个请求,其他对该实例的请求被排队. PerCall,每一线程会分配一个新的服务实例上.不会有并发性问题.不影响吞吐量. PerSess ...
随机推荐
- Elasticsearch的使用场景深入详解
了解了ES的使用场景,ES的研究.使用.推广才更有价值和意义. 1.场景-:使用Elasticsearch作为主要的后端 传统项目中,搜索引擎是部署在成熟的数据存储的顶部,以提供快速且相关的搜索能力. ...
- listview 去掉header和footer中的分割线
在listView中加上android:headerDividersEnabled="false" android:footerDividersEnabled="fals ...
- 基于RBAC的权限设计模型
个部件模型组成,这4个部件模型分别是基本模型RBAC0(Core RBAC).角色分级模型RBAC1(Hierarchal RBAC).角色限制模型RBAC2(Constraint RBAC)和统一模 ...
- HTML5学习笔记三:aside元素,time元素与微格式
一.aside元素 表示当前页面或文章的附属信息部分,相关的引用,侧边栏,广告等有别于主要内容的部分:主要有一下两种用法: 1. 被包含在article元素中作为主要内容的附属信息部分,可以是与当前文 ...
- GOLang(第二篇 发起一个Http请求)
import ( "net/http" "net/url" ) //发送一个简单的get请求 func GetRequest { //联系使用 make(map ...
- Android组件生命周期(二)
引言 应用程序组件有一个生命周期——一开始Android实例化他们响应意图,直到结束实例被销毁.在这期间,他们有时候处于激活状态,有时候处于非激活状态:对于活动,对用户有时候可见,有时候不可见.组件生 ...
- Java经典案例之-“统计英文字母、空格、数字和其它字符的个数”
/** * 描述:输入一行字符串,并且统计出其中英文字母.空格.数字和其它字符的个数. * 分析:利用for语句,条件为输入的字符不为 '\n ' * 作者:徐守威 */ package com.xu ...
- 记一次DG搭建过程中备库ORA-00210,ORA-00202,ORA-27086错误
ORA-00210: cannot open the specified control file ORA-00202: control file: '/u01/app/oracle/oradata/ ...
- jQuery 在Table中选择input之类的东西注意事项
jQuery 在Table中选择input之类的东西注意事项: 如果不在td标签中,是不能进行正确选择的: <table id="tblFormId"> <tr& ...
- jdk自带的动态代理
package com.stone.dp.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Met ...