【问题标题】:Windows service / WCF and threading, beginners questionWindows 服务/WCF 和线程,初学者问题
【发布时间】:2010-11-18 15:20:06
【问题描述】:

我们有一个 Web 服务,它将请求发送到一个 Windows 服务,该服务托管一个 WCF 服务进行处理。

界面简洁:

namespace MyApp
{
    [ServiceContract]
    public interface IMyApp
    {   
        [OperationContract]
        string DoSomething(string xml);
    }
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall)]
    class MyAppWcf : IMyApp
    {
        public string DoSomething(string xml) 
        { 
            Customer customer = GlobalObject.GetCustomer(xml); //millisecs 
            return customer.DoSomething(xml); //Takes 5-10 seconds
        }
    }
}

GlobalObject 在 WindowsService.OnStart() 上实例化,并包含客户对象所需的所有静态数据。 接口 DoSomething() 将被调用到 ca。 30 个不同的客户。

问题:
1. 现在默认的线程行为是什么?每次通话都必须等到最后一个通话结束吗?
2. 更改InstanceContextMode会有什么影响?

真实问题:
最多有 1000 个客户对象,可以并行调用 2 个不同的客户对象,但不能并行调用同一个。例如
DoSomething("客户 1"); => 继续。 10 秒内回答
DoSomething("客户 2"); => 与上述调用并行进行。
DoSomething("客户 2"); => 将等待最后一次调用 DoSomething("Customer 2") 完成

我的服务行为设置应该是什么?我是否必须实施锁定机制以防止同一对象被并行处理多次?

谢谢。

编辑 2:GlobalObject.GetCustomer() 只是从字典中检索 XML 中提到的客户。

【问题讨论】:

    标签: c# multithreading wcf windows-services


    【解决方案1】:

    好的。我不确定我是否知道在使用PerCall 实例化时会忽略ConcurrencyMode,但是查看我自己的项目,我使用PerCall 实例化并且没有为ConcurrencyMode 指定任何值。显然,我确实知道这一点,只是未能在我的代码中记录它。现在已更正。

    我的项目与您描述的非常相似,我使用InstanceContextMode.PerCall,正如我已经提到的那样。这是什么意思。

    • 客户端1 => MyAppWcfInst.DoSomething( "<customer id=A/>" );
    • 客户端2 => MyAppWcfInst.DoSomething( "<customer id=B/>" );
    • 客户端3 => MyAppWcfInst.DoSomething( "<customer id=B/>" );

    所有三个客户端都将同时与您的 WCF 服务交互,但每个客户端都有自己的实例并在单独的线程中运行。因此,虽然每个客户端的每次调用都是单线程的,但它们可以同时处于活动状态。这意味着客户对象的列表可以同时被多个客户端访问。

    Client1 和 Client2 可以并行操作,因为它们处理不同的 Customer 对象,但是 Client3 需要等到 Client2 完成后才能与 CustomerB“做某事”。这意味着您需要在每个 Customer 对象中同步访问。也就是说Customer.DoSomething()方法内部的逻辑需要有一个同步锁来防止多个客户端同时对Customer进行操作。

    class Customer
    {
        private object _sync = new object();
    
        public string DoSomething( string xml )
        {
            lock (_sync)
            {
                // put your logic here...
            }
        }
    }
    

    这就是我的 WCF 服务的工作方式。希望这会有所帮助。

    【讨论】:

    • 谢谢马特,这正是我所需要的。
    【解决方案2】:

    使用 PerCall,您将对服务的请求并行处理,每个请求都在 MyAppWcf 类的不同实例上。如果没有可用的可用 .NET 线程池线程来分派请求,则请求只需等待较早的请求完成。 如果您将其更改为 Single,则请求将被序列化,除非您将 ConcurrencyMode 设置为 Multiple。

    您真正关心的应该是并发访问 GobalObject 方法的安全性:如果这不安全,那么上面的代码也不是。

    Customer.DoSomething 方法也是如此,如果它触及任何共享数据(例如它自己调用 GlobalObject)。

    我不明白您所说的“一次只能处理一个客户对象”是什么意思。如果确实如此,那么您无论如何都需要避免并行执行。

    【讨论】:

    • 可能有 1000 个客户对象。每个客户对象本身都是线程安全的,但不能同时运行同一个对象。例如客户 1 和客户 2 可以并行处理。 GlobalObject.GetCustomer 是安全的(只读)。
    • 关于马特戴维斯的回答......我一直明白,当 InstanceContextMode 为 PerCall 时,ConcurrencyMode 会被忽略,这就是 MSDN 文档所说的。所以我认为你已经有了并行执行......不过,我会检查一下,以防文档有误。
    • +1 @Chris Dickson。我已经根据我显然在途中忘记的信息更新了我的回复。谢谢。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-05
    • 1970-01-01
    • 2012-12-18
    • 1970-01-01
    相关资源
    最近更新 更多