WCF初探-28:WCF中的并发

理解WCF中的并发机制

 

  • 在对WCF并发机制进行理解时,必须对WCF初探-27:WCF中的实例化进行理解,因为WCF中的并发特点是伴随着服务实例上下文实现的。WCF的实例上下文模型可以通过InstanceContext的属性来进行设置,WCF中的并发就是指一个实例上下文处理请求消息的能力,当需要在一个实例上下文中处理多个消息请求时就会产生并发。所以当InstanceContextMode的值为PerSession或Single的时候就会产生并发的情况,这时我们可以通过设置ConcurrencyMode的值来控制服务并发处理消息的模式。
  • ConcurrencyMode指定服务类是支持单线程还是多线程操作模式。具有以下三个值:
  1. Single:服务实例是单线程的,且不接受可重入调用。如果 InstanceContextMode 属性为 Single,且其他消息在实例处理调用的同时到达,则这些消息必须等待,直到服务可用或消息超时为止。
  2. Reentrant:服务实例是单线程的,且接受可重入调用。可重入服务接受在调用其他服务的同时进行调用;因此在调出之前,您需要负责让对象的状态一致,而在调出之后,必须确认本地操作数据有效。请注意,只有通过通道调用其他服务,才能解除服务实例锁定。在此情况下,已调用的服务可以通过回调重入第一个服务。如果第一个服务不可重入,则该调用顺序会导致死锁。
  3. Multiple:服务实例是多线程的。无同步保证。因为其他线程可以随时更改服务对象,所以必须始终处理同步与状态一致性。

 

理解并发模式与实例上下文模式的关系

 

  • 当我们的InstanceContextMode设置为PerSession时,一个客户端会话模型就会产生一个服务实例上下文,此时如果我们的ConcurrencyMode值设置为Single,那么服务将以串行的模式进行消息处理,因为并发模式采用的是单线程模式,所以一次只会处理一个消息,并且同一个实例上下文模型中的线程ID一样。
  • 当我们把InstanceContextMode设置为PerSession,ConcurrencyMode值设置为Multiple时,服务采用多线程处理模型。即一个实例上下文中会出现多个线程来处理消息请求,这样就大大加快程序处理的能力,但不是绝对的。程序的处理能力加大就会对服务器产生消耗,所以在对消息进行并发处理时,我们也要对处理的最大能力进行限制。而已采用多线程模型处理消息时,一定要保证线程时安全的。(这一部分需要各位多线程进行友好的理解)
  • 什么情况下我们才会遇到ConcurrencyMode为Reentrant的情况呢?Single采用的是单线程处理模型,当客户端调用服务端方法时,就会给方法加上锁,如果此时服务端需对客户端产生回调,并且回调的方法采用的是请求\应答的消息模型,当服务对客户端调用完成后,就会尝试重新获取实例上下文模型对接下来的程序逻辑进行处理,并且会对实例上下文进行加锁,但是此时的实例上下文在之前已经被锁住了。回调之前的实例上下文只有在消息处理完成后才能释放锁,而回调后的实例上下文又不能获得锁,导致操作永远无法完成,这就产生了死锁。此时就可以将ConcurrencyMode设置为Reentrant解决此问题。(也可以将ConcurrencyMode设置为Multiple解决此问题,因为设置为Multiple后采用的是多线程处理模型)

 

WCF中的并发模型示例

 

  注意:以后此系列博文如果无特别说明,解决方案都按之前的Client、Host、Service方式进行建立,客户端代理类采用工具Scvutil.exe生成,如果不清楚可以参考此系列之前的博文。

 

  • 此示例采用InstanceContextMode = PerSession, ConcurrencyMode = Single的组合模型,即一个会话产生一个实例上下文,一个实例上下文只有一个线程处理请求。我们通过输出处理请求的实例上下文和线程ID就可以说明此模型的处理情形。参考代码如下:
   using System.ServiceModel;
    using System.Threading;

    namespace Service
    {
        [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession, ConcurrencyMode = ConcurrencyMode.Single)]
        public class SampleMethod:ISampleMethod
        {

            public string MethodOne(string msg)
            {
                OperationContext operationContext = OperationContext.Current;
                InstanceContext instanceContext = operationContext.InstanceContext;
                string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString();
                System.Threading.Thread.Sleep(2000);
                return "You called MethodOne return message is: " + msg + "\n->" + info + "\n->ManagedThreadId:" + 
              Thread.CurrentThread.ManagedThreadId.ToString()+" "+System.DateTime.Now.ToString(); } public string MethodTwo(string msg) { OperationContext operationContext = OperationContext.Current; InstanceContext instanceContext = operationContext.InstanceContext; string info = "InstanceContext HashCode: " + instanceContext.GetHashCode().ToString(); System.Threading.Thread.Sleep(3000); return "You called MethodTwo return message is: " + msg + "\n->" + info + "\n->ManagedThreadId:" +
              Thread.CurrentThread.ManagedThreadId.ToString() + " " + System.DateTime.Now.ToString(); } } }

 

   客户端采用异步方式进行处理,所以Svcutil.exe必须生成异步客户端(svcutil.exe /out:f:\SampleMethodClient.cs /config:f:\App.confighttp://localhost:1234/SampleMethod /a /tcv:Version35),客户端参考代码如下: 

    using System;
    namespace Client
    {
        class Program
        {
            static void Main(string[] args)
            {
                SampleMethodClient client1 = new SampleMethodClient();
                client1.MethodOneCompleted += new EventHandler<MethodOneCompletedEventArgs>(client1_MethodOneCompleted);
                client1.MethodOneAsync("Client1 called MethodOne");
                client1.MethodTwoCompleted += new EventHandler<MethodTwoCompletedEventArgs>(client1_MethodTwoCompleted);
                client1.MethodTwoAsync("Client1 called MethodTwo");

                SampleMethodClient client2 = new SampleMethodClient();
                client2.MethodOneCompleted += new EventHandler<MethodOneCompletedEventArgs>(client2_MethodOneCompleted);
                client2.MethodOneAsync("Client2 called MethodOne");
                client2.MethodTwoCompleted += new EventHandler<MethodTwoCompletedEventArgs>(client2_MethodTwoCompleted);
                client2.MethodTwoAsync("Client2 called MethodTwo");
    
                Console.Read();
            }


            static void client2_MethodOneCompleted(object sender, MethodOneCompletedEventArgs e)
            {
                Console.WriteLine(e.Result.ToString());
            }

            static void client2_MethodTwoCompleted(object sender, MethodTwoCompletedEventArgs e)
            {
                Console.WriteLine(e.Result.ToString());
            }

            static void client1_MethodOneCompleted(object sender, MethodOneCompletedEventArgs e)
            {
                Console.WriteLine(e.Result.ToString());
            }
            static void client1_MethodTwoCompleted(object sender, MethodTwoCompletedEventArgs e)
            {
                Console.WriteLine(e.Result.ToString());
            }
        }
    }

 

  运行结果:

  

  结果说明:

  Client1处理MethodOne和MethodTwo的时间点不同,但是处理的实例上下文ID和线程ID是一致的,这验证了上面的组合处理模型,并且由于客户端产生了两个代理,

  建立了两个会话,所以Client1和Client2的实例上下文ID不一致。

 

  • 接下来,我们将示例采用InstanceContextMode = PerSession, ConcurrencyMode = Multiple的组合模型,让服务采用多线程并发模式处理,代码只需要将 ConcurrencyMode的值改为Multiple,其他的不变,重新编译运行程序。

      运行结果:

  

 

  结果说明:

  Client1处理MethodOne和MethodTwo的时间点不同,虽然处理的实例上下文ID一致,但线程ID是不一致的,这验证了上面的组合处理模型,并且由于客户端产生了两个代理,

  建立了两个会话,所以Client1和Client2的实例上下文ID不一致。

转载于:https://www.cnblogs.com/wangweimutou/p/4643272.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
在C#,可以使用WCF(Windows Communication Foundation)来实现进程间通信。WCF是一种用于构建分布式应用程序的框架,它提供了一种灵活的方式来实现不同进程之间的通信。以下是实现WCF进程间通信的步骤: 1. 定义服务契约接口:在WCF服务,首先需要定义一个服务契约接口,该接口定义了服务的操作和数据契约。在服务契约接口,可以定义需要传递的数据和操作。 2. 实现服务契约接口:在WCF服务,需要实现定义的服务契约接口。在实现过程,可以使用回调方法来实现与客户端的通信。通过OperationContext的方法GetCallbackChannel()来获取回调对象,然后使用回调方法进行通信。 3. 配置WCF服务:在配置文件,需要定义WCF服务的终结点和绑定。终结点定义了服务的地址和协议,绑定定义了服务的通信方式和协议。 4. 创建WCF客户端:在客户端,需要创建一个WCF客户端对象,并指定服务的终结点和绑定。然后可以通过调用客户端对象的方法来与服务进行通信。 5. 调用WCF服务:在客户端,可以通过调用WCF客户端对象的方法来调用WCF服务。如果需要使用回调方法,可以在客户端实现回调契约的接口,并在服务端使用回调方法进行通信。 总结起来,使用WCF实现C#的进程间通信的步骤包括定义服务契约接口、实现服务契约接口、配置WCF服务、创建WCF客户端和调用WCF服务。通过这些步骤,可以实现不同进程之间的通信。[2][3]

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值