WCF是否支持多线程?

时间:2010-07-20 22:56:39

标签: wcf

我开发了一个概念证明应用程序,用于查询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>
    
  4. 客户端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>
    

2 个答案:

答案 0 :(得分:17)

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

[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秒。

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

答案 1 :(得分:0)

尝试更改属性的值

UseSynchronizationContext=false