通过服务端监控结果,说说WCF的并发处理
InstanceContextMode表示的是,WCF允许产生可用来处理包含在传入消息中的调用的服务(契约类)的实例InstanceContext模式数,WCF的并发模式ConcurrencyMode是针对某个封装了服务实例的InstanceContext而言的
简单的说,InstanceContextMode表示产生多少个服务实例对象,ConcurrencyMode表示每个服务实例对象的并发控制模式
InstanceContextMode:调用的服务(契约类)的实例模式有三种
Single 单例模式:每个WCF服务创建一个InstanceContextMode对象,服务开始时创建,服务完成时销毁
PerSession会话模式:每一次会话产生一个InstanceContextMode对象,调用代理的Close方法销毁或者调用IsTerminating服务操作销毁;
PerCall单调模式:每一次请求产生一个InstanceContextMode对象,调用完后进行销毁;
ConcurrencyMode :WCF服务对象(InstanceContextMode)的并发行为有三种
Single:一个封装了服务实例的InstanceContext对象在某个时刻只能用于对某一个单一请求的处理,也就是说对于同一个服务实例的多个调用必须排队,直到上一次调用完成后才能继续;
Reentrant:该模式和Single一样,InstanceContext对象在某个时刻只能用于对某一个单一请求的处理。不过有一点不同的是,如果服务操作在执行过程中涉及对外调用(Call Out),该InstanceContext可以用于其它服务调用请求的处理;。在 Single 模式下,当方法调用另外一个服务(Callback是客户端提供的服务)时,方法会阻塞,直到所调用的服务完成。如果方法不能重入,那么因无法接受所调用服务的返回消息(reply message),无法解除阻塞状态而陷入死锁(deadlock)。Reentrant 模式就是为了解决 Single 的这种不足,允许方法重入以完成处理过程。
Multiple:在该模式下,一个InstanceContext可以同时用于处理多个服务请求,所以Multiple并发模式下针对同一个InstanceContext的多个并发请求能够得到及时的处理。不过,由于是并行的处理方式,服务操作执行过程中状态的管理以及多线程的安全问题需要服务开发者自行处理。
下面通过一个WCF服务端监控程序,来说明三种InstanceContextMode与三种ConcurrencyMode的不同组合所产生的并发结果
1、InstanceContextMode.Single 单例模式,每个WCF服务只产生一个服务(契约类)的实例InstanceContextMode对象
·ConcurrencyMode.Single:服务实例InstanceContext对象在某个时刻只能用于对某一个单一请求的处理。系统自动加锁,无并发问题
WCF启动一个线程4来接收客户端 127.0.0.1:7688的Add方法请求,处理完成后接收来自客户端127.0.0.1:7689的Subtraction请求。WCF是以串行排队模式处理请求的
·ConcurrencyMode.Reentrant:服务实例InstanceContext对象在某个时刻只能用于对某一个单一请求的处理,该模式允许重入单线程并发处理,有可重入(回调)操作时,此模式才会生效,从回调返回的线程会进入队列尾部排队
WCF开启线程4接收客户端127.0.0.1:7582的Add请求,请求处理完成后线程4继续做回调处理,同事开启线程5接收客户端127.0.0.1:7851的请求,这种就是WCF的重入并发机制。
·ConcurrencyMode.Multiple:服务实例InstanceContext可以同时用于处理多个服务请求。系统不会自动加锁,服务操作执行过程中状态的管理以及多线程的安全问题需要服务开发者自行处理
线程4接收客户端127.0.0.1:7895的Add请求,同事开启线程5接收127.0.0.1:7894的请求...
2、InstanceContextMode.PerSession 会话模式 每一次会话产生一个InstanceContextMode对象
·ConcurrencyMode.Single:每个会话会创建一个InstanceContextMode对象实例,每个会话内同时只会有一个线程操作实例,不允许并发。系统自动加锁,无并发问题。
线程4接收客户端127.0.0.1:7904的Add请求,同时线程5接收127.0.0.1:7905的Add请求...这里的单个服务对象实例并不是并发的,虽然我们看到的是多个线程,这里其实每次会话请求只产生一个服务实例对象,因为请求分别来之127.0.0.1:79004-127.0.0.1:7908五个客户端,所以产生了五个服务实例对象。看线程4处理完来至客户端127.0.0.1:7904的Add请求后,才在处理127.0.0.1:7904的Subtraction请求,所以该处理模式在服务实例内部仍是串行的。对会话而言是并行的。
·ConcurrencyMode.Reentrant:每个会话会创建一个InstanceContextMode对象实例,每个会话内同时只会有一个线程操作实例,会话内可接受重入并发。
线程4接收客户端127.0.0.1:7863的Add请求,同时线程5接收127.0.0.1:7864的Add请求...线程4开始执行127.0.0.1:7564的回调请求,同时开启线程3执行来至727.0.0.1:7863的Subtraction请求,这说明,WCF服务实例是重入并发的,但是只有在处理来至同一个客户端的回调请求后才会开启新的线程。
·ConcurrencyMode.Multiple:每个会话会创建一个InstanceContextMode对象实例。每个会话内允许多线程并发,系统不会自动加锁,有并发问题
线程4接收客户端127.0.0.1:7938的Add请求,同时线程5接收127.0.0.1:7864的Add请求,线程6接收客户端127.0.0.1:7938的Substraction请求,从此看出,来至同一个客户化的请求(会话)并没有出现排队想象,而是并行的。
3、InstanceContextMode.PerCall:单调模式 每一次请求产生一个InstanceContextMode对象
·ConcurrencyMode.Single:每一次请求产生一个InstanceContextMode对象,每一个请求内同时只会有一个线程操作实例,不允许并发,系统自动加锁,无并发问题
线程4接收客户端127.0.0.1:8002的Add请求,线程5接收客户端127.0.0.1:8001的请求...线程4处理完客户端127.0.0.1:8002的Add请求后,开启线程9接收来至同一客户端127.0.0.1:8002的Subtraction请求,看出每一次请求都会产生一个新的服务实例对象。因为有多客户端所以产生多个服务实例对象,这里表现出一种对外的并行,但是因为服务实例对象不允许并发所以虽然127.0.0.1:8002的Add请求和Subtraction请求是来至同一个客户端的仍出现了排队的现象。
·ConcurrencyMode.Reentrant:每一次请求产生一个InstanceContextMode对象,每个请求内同时只会有一个线程操作实例,会话内可接受重入并发。当有回调操作时如果使用Single并发模式的话就会产生死锁(1、调用服务端;2、回调客户端;3、返回服务端,1的时候锁定了,到3的时候就无法执行了,所以死锁了),此时应该用Reentrant并发模式
线程4接收客户端127.0.0.1:7884的Add请求,同时线程5接收来之客户端127.0.0.1:7883的请求,因为是单调的所以,在新的线程6中接收来至客户端127.0.0.1:7884的Subtraction请求,线程4结束客户端客户端127.0.0.1:7884的Add请求,开始处理127.0.0.1:7884的Add的回调请求,在回调请求处理同时,线程6还在处理127.0.0.1:7884的Subtraction请求,这里表现出了回调的并发。
·ConcurrencyMode.Multiple:每一次请求产生一个InstanceContextMode对象。每个请求内允许多线程并发,系统不会自动加锁,有并发问题
线程4接收来自客户端127.0.0.1:3460的Add请求 线程5接收来至客户端127.0.0.1:3461的Add请求...同时线程6接收客户端127.0.0.1:3460的Subtraction请求,来至同一个客户端127.0.0.1:3460的Add请求与Subtraction请求没有出现排队现象,这里是并发的。