【问题标题】:Does WCF support Multi-threading itself?WCF 本身是否支持多线程?
【发布时间】:2010-07-20 22:56:39
【问题描述】:

我开发了一个概念验证应用程序,用于查询 WCF 是否支持多线程。

现在,我所做的只是创建一个标有

的服务合同
 [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single,
                  ConcurrencyMode = ConcurrencyMode.Multiple, 
                  UseSynchronizationContext = true)]

使用两个操作来获取固定文本。 第一种方法Thread.Sleep 8 秒延迟响应,另一种直接返回数据。

我遇到的问题是,当我运行两个客户端应用程序实例并从第一个客户端请求延迟的方法并从第二个客户端请求另一个方法时,我得到了顺序响应。

当服务忙于处理另一个请求时,如何从服务获取响应?

 namespace WCFSyncService
 {
    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)], 
                 ConcurrencyMode = ConcurrencyMode.Multiple, 
                 UseSynchronizationContext = true)]

    public class ServiceImplementation : IService

    {
        public ServiceImplementation()
        {
        }

        #region IService Members

        public string GetDelayedResponse()
        {
            System.Threading.Thread.Sleep(8000);
            return "Slow";
        }

        public string GetDirectResponse()
        {
            return "Fast";
        }

        #endregion
    }
}

我需要同时调用GetDelayedResponseGetDirectResponse方法,并在8秒结束前得到“快速”文本。


托管应用程序代码

namespace ServiceHostApplication
{
    public partial class frmMain : Form
    {
        private WCFSessionServer.IService oService;

        public frmMain()
        {
            InitializeComponent();
        }

        private void btnStartService_Click(object sender, EventArgs e)
        {
            ServiceHost objSvcHost;

            oService = new WCFSessionServer.ServiceImplementation();
         objSvcHost = new ServiceHost( typeof(WCFSessionServer.ServiceImplementation));
            objSvcHost.Open();
        }
    }
}

下面是我实现它来测试案例的代码:

服务器端类,

  1. 服务接口

    namespace WCFSessionServer
    {
        [ServiceContract]
        public interface IService
    
        {
            [OperationContract]
            string GetDelayedResponse();
    
           [OperationContract]
           string GetDirectResponse();
        }
     }
    
  2. 实现类

    namespace WCFSessionServer
    {
       [ServiceBehavior(
                        InstanceContextMode = InstanceContextMode.PerCall,
                        ConcurrencyMode =   ConcurrencyMode.Multiple,
                        UseSynchronizationContext =  true)]
        public class ServiceImplementation : IService
         {
             public ServiceImplementation()
                {
                }
    
             #region Service Members
             public string GetDelayedResponse()
                {
                 System.Threading.Thread.Sleep(8000);
                 return "Slow";
                }
    
             public string GetDirectResponse()
             {
                 return "Fast";
             }
             #endregion
         }
     }
    
  3. 服务器端 app.config

    <system.serviceModel>
     <services>
      <service 
                behaviorConfiguration = "WCFSessionServer.IService"  
                name = "WCFSessionServer.ServiceImplementation" >
      <endpoint address="http://localhost:2020/SessionService/basic/"
                behaviorConfiguration="WCFSessionServer.IService"
                binding="basicHttpBinding"
                name="BasicHttpBinding_IService"
                bindingName="myBasicHttpBinding"
                contract="WCFSessionServer.IService" />
      <endpoint address="mex"
                binding="mexHttpBinding"
                contract="IMetadataExchange" />
      <host>
       <baseAddresses>
         <add baseAddress="http://localhost:2020/SessionService/" />
       </baseAddresses>
      </host>
    </service>
     </services>
          <behaviors>
          <endpointBehaviors>
           <behavior name="TimeOut">
            <callbackTimeouts transactionTimeout="00:00:02"/>
          </behavior>
         <behavior name="WCFSessionServer.IService" >
           <dataContractSerializer maxItemsInObjectGraph="2147483647" />
         </behavior>
       </endpointBehaviors>
       <serviceBehaviors>
        <behavior name="WCFSessionServer.IService">
           <serviceThrottling    maxConcurrentCalls="10"
                                 maxConcurrentSessions="10"
                                 maxConcurrentInstances="10"/>
               <dataContractSerializer maxItemsInObjectGraph="2147483647" />
               <serviceMetadata httpGetEnabled="True"/> 
               <serviceDebug includeExceptionDetailInFaults="True" />
             </behavior>
           </serviceBehaviors>
         </behaviors>
       </system.serviceModel>
    

客户端app.config

    <system.serviceModel>
          <bindings>
              <basicHttpBinding>
                  <binding name="BasicHttpBinding_IService"
                           closeTimeout="00:01:00"
                           openTimeout="00:01:00"
                           receiveTimeout="00:10:00"
                           sendTimeout="00:01:00"
                           allowCookies="false"
                           bypassProxyOnLocal="false"
                           hostNameComparisonMode="StrongWildcard"
                           maxBufferSize="65536"
                           maxBufferPoolSize="524288"
                           maxReceivedMessageSize="65536"
                           messageEncoding="Text"
                           textEncoding="utf-8"
                           transferMode="Buffered"
                           useDefaultWebProxy="true">
                           <readerQuotas maxDepth="32"
                                         maxStringContentLength="8192"
                                         maxArrayLength="16384"
                                         maxBytesPerRead="4096"
                                         maxNameTableCharCount="16384" />
                    <security mode="None">
                    <transport
                              clientCredentialType="None"
                              proxyCredentialType="None"
                              realm="" />
                    <message 
                             clientCredentialType="UserName"
                             algorithmSuite="Default" />
                </security>
            </binding>
        </basicHttpBinding>
    </bindings>
    <client>
        <endpoint address="http://localhost:2020/SessionService/basic/"
                  binding="basicHttpBinding"
                  bindingConfiguration="BasicHttpBinding_IService"
                  contract="SessionServiceProxy.IService"
                  name="BasicHttpBinding_IService" />
    </client>
</system.serviceModel>

【问题讨论】:

  • 请停止大喊大叫!

标签: wcf


【解决方案1】:

好吧,通过将你的服务定义为

[ServiceBehavior(InstanceContextMode=InstanceContextMode.Single, 
                 ConcurrencyMode=ConcurrencyMode.Multiple, 
                 UseSynchronizationContext=true)] 

您基本上将您的服务类定义为单例 (InstanceContextMode.Single),这当然不是最好的方法。通过将其定义为 ConcurrencyMode.Multiple,您可以使其成为一个多线程单例 - 这将确保您的代码是 200% 线程安全的大量负担放在您自己的肩上。

我的建议是将您的服务实现类标记为每次调用。

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

使用这种方法,WCF 运行时本身将根据需要启动尽可能多的服务实例类,以处理您的请求。在您的示例中,WCF 运行时将创建并启动 ServiceImplementation 的两个实例,一个用于每个请求,并同时处理调用。最大的优势是:由于每个服务实例类只处理一个请求,因此您无需担心代码中的并发管理 - 您在“单线程”类中,WCF 运行时处理与有多个请求并适当地处理它们。

更新:您仍然没有展示您是如何创建客户端服务代理的,以及您是如何调用服务的。您已经发布了几乎所有的服务器端代码,但没有发布一点客户端代码。

好的,方法如下:

  • 启动您的服务主机并确保它正在运行
  • 在 Visual Studio 中,为您的客户创建两个单独的控制台应用程序项目 - 称它们为 Client1Client2
  • 在这两个新客户端项目中,使用 Add Service Reference 为您的服务添加服务引用
  • 这将在“服务参考”地球下创建一堆文件

  • 您现在需要在两个客户端项目中实例化客户端代理的实例:

     In Client1:
         var instance1 = new ServiceImplementationClient();
    
     In Client2:
         var instance2 = new ServiceImplementationClient();
    
  • Client1 将调用您的第一个方法GetDelayedResponse,而Client2 将调用GetDirectResponse

     In Client1:
         instance1.GetDelayedResponse();
    
     In Client2:
         instance2.GetDirectResponse();
    
  • 如果您同时运行这两个应用程序,您应该会看到 Client2 立即返回,而 Client1 将等待这 8 秒。

如果您有两个完全独立的客户端,并且它们将在服务器上获得一个完全独立的服务实例,那么它们将完全相互独立,不会序列化它们的调用,也不会相互阻塞。

【讨论】:

  • 您好,不幸的是,在我更改了您上面推荐的内容后,该行为仍然按顺序处理。有什么建议吗?
  • 您需要向我们展示更多代码以进行进一步诊断。你的 web.config/app.config 是什么样的?你如何调用这个 WCF 服务?
  • @Sabri Ghaith:我很想看看如何你从你的客户那里调用那个服务,你说事情仍然是序列化的......
  • @marc_s ,请参阅我刚刚发布的代码并给我您的反馈或给我一个解决方案,以证明我获得多线程 wcf 服务的概念。
  • @marc_s。好吧,我刚刚看到你的帖子,并愿意测试它。好吧,我正在运行同一个 Windows 应用程序(客户端)的两个实例来调用不同的方法。
【解决方案2】:

尝试改变属性的值

UseSynchronizationContext=false 

【讨论】:

  • 非常感谢,你拯救了我的一天。我发现如果这个标志不是 FALSE,传入调用会窃取 UI 线程,并且应用程序会因其他调用而变得无响应。我不明白为什么,但关闭此功能后,UI 和其他调用现在都可以响应,就像在真正的多线程应用程序中一样。
  • 谁能解释一下将它设置为 false 覆盖默认值的缺点?
猜你喜欢
  • 1970-01-01
  • 2018-05-29
  • 1970-01-01
  • 1970-01-01
  • 2014-02-09
  • 1970-01-01
  • 2020-10-01
  • 2012-03-25
  • 1970-01-01
相关资源
最近更新 更多