代码之家  ›  专栏  ›  技术社区  ›  Brandon Linton

当使用wcf服务行为属性设置为concurrencyMode.multiple和instanceContextMode.perCall时,是否可能出现并发问题?

  •  23
  • Brandon Linton  · 技术社区  · 15 年前

    我们有一个WCF服务,可以进行大量事务性的nhibernate调用。有时我们会看到SQL超时,即使调用正在更新不同的行,并且表被设置为行级锁定。

    在挖掘日志之后,看起来不同的线程正在代码中输入相同的点(我们的事务使用块),提交时挂起了更新。但是,它没有意义,因为我们认为以下服务类属性在每个服务调用中强制使用一个唯一的执行线程:

    [ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall)]
    

    我们最近将并发模式改为 ConcurrencyMode.Single 而且还没有遇到任何问题,但是这个bug很难复制(如果有人想把这样的bug冲掉,请告诉我!).

    无论如何,这一切都让我想到了我的问题:PerCall的InstanceContextMode是否应该在服务中强制线程安全,即使ConcurrencyMode设置为多个?两个调用如何可能由同一个服务实例提供服务?

    谢谢!

    4 回复  |  直到 13 年前
        1
  •  24
  •   Matt Davis    13 年前

    拥有两个不同的WCF客户机(即代理)引用同一个WCF服务实例的唯一方法是使用 InstanceContextMode=InstanceContextMode.Single . 如果缩放是一个问题,那么这是一个糟糕的选择,因此您要使用 PerCall 如果可以的话。

    当你使用 珀卡尔 , 每个 呼叫 到wcf服务获取其自己的wcf服务实例 . 服务实例没有共享,但这并不意味着它们不共享相同的后端存储(如数据库、内存、文件等)。记住, 珀卡尔 允许每个 呼叫 以同时访问您的WCF服务。

    这个 ConcurrencyMode 设置控制服务本身的线程模型。设置 Single 限制所有WCF服务实例在同一线程上运行。因此,如果同时连接多个客户机,那么在WCF服务端,它们一次只能执行一个。在这种情况下,您可以利用WCF来提供同步。正如您所看到的,它可以很好地工作,但可以将其视为对同步只有宏级控制—每个WCF服务调用将在下一个调用可以执行之前全部执行。

    设置 并发模式 Multiple 但是,将允许所有WCF服务实例同时执行。在这种情况下, 您负责提供必要的同步 . 可以将其视为对同步具有微级别控制,因为您只能同步每个调用中需要同步的那些部分。

    我希望我已经解释得足够好了,但是这里有一小段关于 并发模式 以防万一:

    将concurrencyMode设置为single将指示系统限制 一个线程的服务实例 一次执行,释放 你从处理线程 问题。倍数的值意味着 服务对象可以由 一次多个线程。在 这种情况下,必须确保螺纹 安全。

    编辑

    你问的

    那么,在使用concurrencyMode.single时,使用percall和single是否会提高性能?或者反过来是真的?

    这可能取决于服务。

    InstanceContextMode.PerCall ,将通过代理为每个调用创建一个新的服务实例,因此您需要处理实例创建的开销。假设您的服务构造函数做的不多,这不会是问题。

    InstanceContextMode.Single ,在应用程序的生命周期内只存在一个服务实例,因此几乎没有与实例创建相关的开销。但是,此模式只允许一个服务实例处理将要进行的每个调用。因此,如果同时进行多个调用,则每个调用都必须等待其他调用完成,然后才能执行。

    值得一提的是,我是这样做的。使用 珀卡尔 实例上下文 多个 并发性。在WCF服务类内部,创建静态成员以管理后端数据存储,然后根据需要使用 lock 声明, volatile 字段等。这允许您的服务在保持线程安全的同时能够很好地扩展。

        2
  •  7
  •   Matt Davis    15 年前

    我相信答案是有多个线程(在客户端)使用同一代理实例,因此可能允许对同一实例进行多个调用。这个 post 有更详细的解释。

        3
  •  2
  •   Valentin Kuzub    14 年前

    InstanceContextMode.PerCall ConcurrencyMode.Single 如果您没有在服务器上使用双向回调,应该可以。在这种情况下,你需要使用 ConcurrencyMode.Reentrant 否则回调将无法访问锁定的服务实例,并且将发生死锁。

    因为它是一个每次调用服务实例的创建,所以其他线程或调用不可能访问它。如其他答案中提及的第条所述 article 如果会话是在绑定级别上创建的,并且您使用的是同一个服务代理对象,那么这种组合仍然是一个问题。

    因此,如果您不使用相同的代理对象或没有sessionful绑定,并且不使用客户端的双向回调(很可能它们应该是单向的)。 InstanceContextMode.PerCall实例 并发模式.single 应该是好的。

        4
  •  1
  •   Dayakar D.N    13 年前

    我认为这完全取决于要求。 如果我们要多次呼叫同一个服务,那么我们可以更好地使用 InstanceContextMode是单一的,ConcurrencyMode是多个的。