【问题标题】:Why can this WCF service serve only one request at a time?为什么这个 WCF 服务一次只能处理一个请求?
【发布时间】:2014-09-10 07:51:49
【问题描述】:

我看过几个类似的问题,但根据他们的回答我无法解决这个问题。

我有以下 WCF 服务用于在同一服务器上运行的应用程序之间进行通信,请注意 ConcurrencyMode 设置为 Multiple

[ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, UseSynchronizationContext = false, ConcurrencyMode = ConcurrencyMode.Multiple)]
internal class MyService : ServiceBase, IMyService
{
    ...
}

我们有一个 WPF 应用程序,我们在其中通过以下方式创建服务实例:

var serv = new MyService();

var servHost = new ServiceHost(serv, new Uri("..."));

servHost.AddServiceEndpoint(typeof(IMyService), ServiceBase.DefaultInterProcessBinding, string.Empty);

servHost.Open();

其中 ServiceBase.DefaultInterProcessBinding 如下:

public static readonly Binding DefaultInterProcessBinding = new NetNamedPipeBinding()
{
    CloseTimeout = TimeSpan.FromHours(1),
    OpenTimeout = TimeSpan.FromHours(1),
    ReceiveTimeout = TimeSpan.MaxValue,
    SendTimeout = TimeSpan.FromHours(1),
    HostNameComparisonMode = HostNameComparisonMode.StrongWildcard,
    MaxBufferSize = 1073741824,
    MaxBufferPoolSize = 524288,
    MaxReceivedMessageSize = 1073741824,
    TransferMode = TransferMode.Buffered,
    ReaderQuotas = new XmlDictionaryReaderQuotas()
    {
            MaxDepth = 32,
            MaxStringContentLength = 8192,
            MaxArrayLength = 16384,
            MaxBytesPerRead = 4096,
            MaxNameTableCharCount = 16384
    }
};

当我们向该服务并行发送多个请求时,由于某种原因,它一次只处理一个请求。 (确定性测试很容易,因为我们有相当长的运行请求,所以可以非常清楚地看到我们在客户端并行调用了 3 个请求,而在服务器端,它们一次一个地被顺序处理。 )

这可能是什么原因?我应该检查哪些其他配置参数?

(更新:我从客户端调用服务的代码与此类似:

Task.Factory.StartNew(() =>
    {
        serviceClient.Foo();
    });
Task.Factory.StartNew(() =>
    {
        serviceClient.Bar();
    });
Task.Factory.StartNew(() =>
    {
        serviceClient.Baz();
    });

通过调试我可以看到,所有三个请求都被立即调用,但它们在服务器上一次处理一个。)

更新 2:问题可能不在服务器上,而在客户端上。如果我为调用创建一个新的客户端对象,那么它们会被正确地并行处理。我通过以下方式创建客户端:

var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));

serviceClient = factory.CreateChannel();

我应该在工厂或频道上配置其他东西吗?

【问题讨论】:

    标签: c# .net wcf concurrency


    【解决方案1】:

    我发现问题不在于服务器,而在于客户端。

    看来,如果您创建一个带有ChannelFactory 的频道,您必须在其上显式调用Open()。否则框架会在你每次调用请求时调用EnsureOpened(),而EnsureOpened() 将阻塞直到前一个请求完成,因此实际上一次只会发送一个请求。
    (详情请看:http://blogs.msdn.com/b/wenlong/archive/2007/10/26/best-practice-always-open-wcf-client-proxy-explicitly-when-it-is-shared.aspx

    所以修改这段代码

    var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));
    
    serviceClient = factory.CreateChannel();
    

    到这里:

    var factory = new ChannelFactory<IMyService>(ServiceBase.DefaultInterProcessBinding, new EndpointAddress("..."));
    
    serviceClient = factory.CreateChannel();
    ((IClientChannel)serviceClient).Open();
    

    解决了问题,现在请求可以正确并行发送。

    (顺便说一句,我需要大量的谷歌搜索才能找到这个解决方案,我很奇怪为什么这个问题在 MSDN 上没有得到更强烈的宣传。)

    【讨论】:

    • 您是否尝试在您的ChannelFactory 上拨打Open
    • +1 好的,谢谢马克。这很有帮助。另一个快速的问题。您是否在每个线程中使用不同的通道实例?频道的制作成本很低。
    • 不,这样它可以在具有单个通道对象的多个线程中工作。我想多个通道也可以工作(例如,我考虑过使用带有ThreadStaticAttribute 的静态字段,或者使用ThreadLocal&lt;T&gt; 对象)。
    • 确保缓存通道工厂。做起来很贵。我真的希望他们在 msdn 中提供更多关于某些对象生命周期的详细信息……
    猜你喜欢
    • 2019-01-18
    • 1970-01-01
    • 1970-01-01
    • 2017-03-17
    • 1970-01-01
    • 2020-07-12
    • 2018-07-28
    • 2019-05-11
    • 1970-01-01
    相关资源
    最近更新 更多