博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
用实例浅谈WCF实例与并发
阅读量:6149 次
发布时间:2019-06-21

本文共 4085 字,大约阅读时间需要 13 分钟。

并发是对同时执行的任务数量的度量,单位为任务(如请求、作业、事务等)。执行时间是对完成任务所用时间的度量,单位为时间(如毫秒、秒等)。吞吐量是在固定的时间内完成的任务数量的度量,单位为任务/时间(如请求/秒、事务/秒等)。可以通过减少执行时间或提高并发来提高吞吐量。在WCF中可以通过InstanceContextMode和ConcurrencyMode来控制并发行为。

InstanceContextMode用于控制服务类实例化,可以有以下几种取值:

Single:一个服务类实例处理所有客户端的所有请求。

PerCall:为每一个客户端的每一个请求创建一个服务类实例。

PerSession:为每一个客户端会话创建一个服务类实例(也就是每一个客户端会话的所有请求共用一个服务类实例)。

ConcurrencyMode用来控制服务类实例内的线程并发。有以下取值:

Single:在同一时刻只有一个线程可以访问服务类实例。

Reentrant:在同一时刻只有一个线程访问服务类实例,但是线程能暂时离开服务类实例,稍后回来并继续访问。

Mutiple:多线程能并发访问服务类实例。

下面用简单的代码来展示InstanceContextMode和ConcurrencyMode不同的设置组合对服务类实例化和并发的影响。这次用NetTcpBinding绑定,它支持会话。

服务契约:

 
using
System;
using
System.ServiceModel;
namespace
IFruitSvc
{
[ServiceContract(Namespace
=
"
http://www.cnblogs.com/qiuwuyu
"
)]
public
interface
IFruitService
{
[OperationContract]
string
GetFruitName();
}
}

服务类:

 
using
System;
using
System.ServiceModel;
using
IFruitSvc;
using
System.Threading;
using
System.ServiceModel.Description;
namespace
FruitSvc
{
public
class
FruitService:IFruitService
{
FruitService()
{
Console.WriteLine(
"
{0} : Created new instance of FruitService on thread
"
, DateTime.Now.Ticks);
}
public
string
GetFruitName()
{
Console.WriteLine(
"
{0} : GetFruitName called on thread {1}
"
, DateTime.Now.Ticks,
Thread.CurrentThread.ManagedThreadId);
return
"
banana
"
;
}
}
}

服务端寄存:

 
using
System;
using
System.ServiceModel;
using
System.ServiceModel.Description;
using
IFruitSvc;
using
FruitSvc;
namespace
WcfInstanceHost
{
class
Program
{
static
void
Main(
string
[] args)
{
using
(ServiceHost host
=
new
ServiceHost(
typeof
(FruitService),
new
Uri(
"
net.tcp://localhost:8000
"
)))
{
ServiceEndpoint sed
=
host.AddServiceEndpoint(
typeof
(IFruitService),
new
NetTcpBinding(),
"
FruitService
"
);
//
设置IFruitService的ServiceContract特性的SessionMode
sed.Contract.SessionMode
=
SessionMode.Allowed;
ServiceMetadataBehavior behavior
=
new
ServiceMetadataBehavior();
host.Description.Behaviors.Add(behavior);
ServiceBehaviorAttribute behaviorAttr
=
host.Description.Behaviors.Find
<
ServiceBehaviorAttribute
>
();
if
(behaviorAttr
==
null
)
{
behaviorAttr
=
new
ServiceBehaviorAttribute();
}
//
设置服务类FruitService的ServiceBehavior特性的ConcurrencyMode和InstanceContextMode
behaviorAttr.ConcurrencyMode
=
ConcurrencyMode.Single;
behaviorAttr.InstanceContextMode
=
InstanceContextMode.PerCall;
host.AddServiceEndpoint(
typeof
(IMetadataExchange),
MetadataExchangeBindings.CreateMexTcpBinding(),
"
mex
"
);
host.Open();
Console.WriteLine(
"
Fruit Service Is Running...
"
);
Console.ReadLine();
}
}
}
}

运行此控制台程序,用如下命令生成代理和配置文件

2011042210241617.jpg

“/a”是为了生存异步调用方法。而后把生存的两个文件添加到客户端项目内。

客户端调用代码:

 
using
System;
using
System.Threading;
namespace
WcfInstanceClient
{
class
Program
{
static
void
Main(
string
[] args)
{
FruitServiceClient proxy
=
new
FruitServiceClient();
for
(
int
i
=
0
; i
<
4
; i
++
)
{
Console.WriteLine(
"
{0}: Begin Calling GetFruitName
"
, DateTime.Now.Ticks);
proxy.BeginGetFruitName(GetFruitNameCallBack, proxy);
}
Console.ReadLine();
}
static
void
GetFruitNameCallBack(IAsyncResult ar)
{
string
name
=
((FruitServiceClient)ar.AsyncState).EndGetFruitName(ar);
Console.WriteLine(
"
{0}: End FruitName:{1}
"
, DateTime.Now.Ticks, name);
}
}
}

首先设置ConcurrencyMode.Single和InstanceContextMode.PerCall 这种组合设置会为每次调用生成一个服务类实例。

运行结果:

2011042210245772.jpg

下面用ConcurrencyMode.Single和InstanceContextMode.PerSession测试下,结果应该是每个客户会话一个服务类实例,这次启动两个客户端,应该只有两个服务类实例。

执行结果,服务端:

2011042210254020.jpg

客户端:

2011042210264875.jpg

下面我们用ConcurrencyMode.Multiple和InstanceContextMode.PerSession进行测试,因为同一会话中允许多个线程并发访问,所以需要手工控制访问的安全性。

修改服务类代码如下:

 
public
class
FruitService:IFruitService
{
//
添加一对象,对此对象访问加锁
object
lockObj
=
new
object
();
private
int
n
=
0
;
FruitService()
{
Console.WriteLine(
"
{0} : Created new instance of FruitService on thread
"
, DateTime.Now.Ticks);
}
public
string
GetFruitName()
{
string
name
=
"
banana
"
;
Console.WriteLine(
"
{0} : GetFruitName called on thread {1}
"
, DateTime.Now.Ticks,
Thread.CurrentThread.ManagedThreadId);
lock
(lockObj)
{
name
=
name
+
"
_
"
+
(
++
n).ToString();
}
return
name;
}
}

程序的执行结果(还是运行两个客户端)服务端:

2011042210274489.jpg

客户端:

2011042210284745.jpg

假如把InstanceContextMode设置为PerCall那将都会是1。还有几种组合就不一一测试。

转载于:https://www.cnblogs.com/qiuwuyu/archive/2011/04/22/2024458.html

你可能感兴趣的文章
Windows Server已可安装Docker,Azure开始支持Mesosphere
查看>>
简洁优雅地实现夜间模式
查看>>
react学习总结
查看>>
微软正式发布PowerShell Core 6.0
查看>>
Amazon发布新的会话管理器
查看>>
InfoQ趋势报告:DevOps 和云计算
查看>>
舍弃Python,为什么知乎选用Go重构推荐系统?
查看>>
在soapui上踩过的坑
查看>>
MySQL的字符集和字符编码笔记
查看>>
ntpd同步时间
查看>>
must implement java.io.Serializable hessian
查看>>
Microsoft Licenses Flash Lite for Windows Mobile Users
查看>>
HDOJ 2020 绝对值排序
查看>>
HDOJ/HDU 2560 Buildings(嗯~水题)
查看>>
Maven编译时跳过Test
查看>>
Spring Boot 整合Spring Security 和Swagger2 遇到的问题小结
查看>>
[20170628]12C ORA-54032.txt
查看>>
除以2
查看>>
高可用集群原理解析
查看>>
Nginx配置URL转向tomcat
查看>>