2012-07-31 47 views
1

我已经迈出了使用WCF开发WINDOWS服务托管计算引擎的第一步。该服务工作的很好,但它似乎只使用一个线程为我所有的电话,但我需要它是可扩展的,并使用多线程。自托管的WCF服务:ConcurrencyMode.Multiple但仅使用一个线程?

忽略代码中的所有跟踪等,因为它是这个应用程序的非常早期的阶段。

它调用一些在服务启动时将信息读入内存的第三方软件(ThirdParty.Initialise(strInit)),然后每次调用ProcessInformation都会返回给定XML字符串的计算结果。

到目前为止,无论我设置ServiceBehavior atts以及无论使用多少独立的消费者,所有调用都只使用一个线程 - 任何人都可以提供帮助吗?

代码概述:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.PerCall, UseSynchronizationContext = false)] 
public class TestWCFService : ITestWCFService 
{ 
    private static ThirdPartyLib.ThirdPartyComClass ThirdParty; 

    private static bool initCalled = false; 
    private static int cntInit = 0; 
    private static int cntTrans = 0; 

    public TestWCFService() 
    { 
     if (ThirdParty == null) 
     { 
      ThirdParty = new ThirdPartyLib.ThirdPartyComClass(); 
     } 
    } 

    public bool InitialiseThirdParty(string strInit, out string strError) 
    { 
     try 
     { 
      if (!initCalled) 
      { 
       cntInit++; 
       ThirdParty.Initialise(strInit); 
       initCalled = true; 
      } 
      strError = "Call Num " + cntInit; 
      return true; 
     } 
     catch (Exception ex) 
     { 
      strError = "ThirdParty.Initialise exception " + ex.Message + " 0n call number " + cntInit; 
      return false; 
     } 
    } 

    public bool ProcessInformation(string strRequestXML, int quoteMarker, out string strResponseXML, out string strError, out int quoteMarkerReturned) 
    { 
     try 
     { 
      cntTrans++; 
      quoteMarkerReturned = quoteMarker; 
      ThirdParty.ProcessInformation(strRequestXML, out strResponseXML); 
      strError = "Call Trans Num " + cntTrans; 
      return true; 
     } 
     catch (Exception ex) 
     { 
      strError = ex.Message + " On call trans num " + cntTrans; 
      strResponseXML = "Error"; 
      quoteMarkerReturned = quoteMarker; 
      return false; 
     } 
    } 
} 

配置:

<?xml version="1.0" encoding="utf-8" ?> 
<configuration> 
    <system.web> 
    <compilation debug="true" /> 
    </system.web> 
    <system.serviceModel> 
    <bindings> 
     <wsHttpBinding> 
     <binding name="TestServiceBinding" bypassProxyOnLocal="true" 
      useDefaultWebProxy="false"> 
      <readerQuotas maxDepth="524288" maxStringContentLength="524288" 
      maxArrayLength="524288" maxBytesPerRead="524288" maxNameTableCharCount="524288" /> 
      <reliableSession inactivityTimeout="00:30:00" enabled="true" /> 
     </binding> 
     </wsHttpBinding> 
     <mexHttpBinding> 
     <binding name="MEXTestServiceBinding" openTimeout="00:02:00" 
      sendTimeout="00:02:00" /> 
     </mexHttpBinding> 
    </bindings> 
    <services> 
     <service behaviorConfiguration="TestWcfServiceLibrary.TestWCFServiceBehavior" 
     name="TestWcfServiceLibrary.TestWCFService"> 
     <endpoint address="" binding="wsHttpBinding" bindingConfiguration="TestServiceBinding" 
      name="" contract="TestWcfServiceLibrary.ITestWCFService"> 
      <identity> 
      <dns value="localhost" /> 
      </identity> 
     </endpoint> 
     <endpoint address="mex" binding="mexHttpBinding" bindingConfiguration="MEXTestServiceBinding" 
      contract="IMetadataExchange" /> 
     <host> 
      <baseAddresses> 
      <add baseAddress="http://localhost:8731/Design_Time_Addresses/TestWcfServiceLibrary/TestWCFService/" /> 
      </baseAddresses> 
     </host> 
     </service> 
    </services> 
    <behaviors> 
     <serviceBehaviors> 
     <behavior name="TestWcfServiceLibrary.TestWCFServiceBehavior"> 
      <serviceMetadata httpGetEnabled="True"/> 
      <serviceThrottling maxConcurrentCalls="100" maxConcurrentSessions="100" maxConcurrentInstances="100"/> 
      <serviceDebug includeExceptionDetailInFaults="False" /> 
     </behavior> 
     </serviceBehaviors> 
    </behaviors> 
    </system.serviceModel> 
</configuration> 
+0

你怎么知道只有一个线程被使用?我猜想你的第三方COM组件是Apartment线程,因此具有线程关联性,所以无论服务实现使用多少.NET线程,它们都必须排队以使用唯一的STA线程能够调用COM对象。 – 2012-07-31 12:32:13

回答

1

每微软文档:

使用并发的是有关实例化模式。在PerCall 实例中,并发性并不相关,因为每个消息都是由新服务实例处理的 。

// Multiple allows concurrent processing of multiple messages by a service instance. 
// The service implementation should be thread-safe. This can be used to increase throughput. 
[ServiceBehavior(ConcurrencyMode=ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)] 

// Uses Thread.Sleep to vary the execution time of each operation. 
public class CalculatorService : ICalculatorConcurrency 
{ 
    int operationCount; 

    public double Add(double n1, double n2) 
    { 
     operationCount++; 
     System.Threading.Thread.Sleep(180); 
     return n1 + n2; 
    } 

    public double Subtract(double n1, double n2) 
    { 
     operationCount++; 
     System.Threading.Thread.Sleep(100); 
     return n1 - n2; 
    } 

    public double Multiply(double n1, double n2) 
    { 
     operationCount++; 
     System.Threading.Thread.Sleep(150); 
     return n1 * n2; 
    } 

    public double Divide(double n1, double n2) 
    { 
     operationCount++; 
     System.Threading.Thread.Sleep(120); 
     return n1/n2; 
    } 

    public string GetConcurrencyMode() 
    { 
     // Return the ConcurrencyMode of the service. 
     ServiceHost host = (ServiceHost)OperationContext.Current.Host; 
     ServiceBehaviorAttribute behavior = host.Description.Behaviors.Find<ServiceBehaviorAttribute>(); 
     return behavior.ConcurrencyMode.ToString(); 
    } 

    public int GetOperationCount() 
    { 
     // Return the number of operations. 
     return operationCount; 
    } 
} 

输出示例:([]中的数字表示螺纹ID)

2012-07-31 09:07:28,509 [9] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 752.919376325402 
2012-07-31 09:07:28,512 [17] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 752.919376325402 
2012-07-31 09:07:28,524 [13] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 2143.10173334651 
2012-07-31 09:07:28,524 [11] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 15.5665354410031, double n2 = 48.3678194919451) 
2012-07-31 09:07:28,532 [22] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 94.7194438868758, double n2 = 29.8120223590229) 
2012-07-31 09:07:28,534 [9] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 99.2045067247024, double n2 = 88.4957458770349) 
2012-07-31 09:07:28,539 [4] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 99.2045067247024, double n2 = 88.4957458770349) 
2012-07-31 09:07:28,539 [7] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 37.991849630136, double n2 = 41.7864370820049) 
2012-07-31 09:07:28,539 [17] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Entering: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double n1 = 11.331077670367, double n2 = 55.5888338273339) 
2012-07-31 09:07:28,539 [11] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 752.919376325402 
2012-07-31 09:07:28,539 [22] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 2823.77817898976 
2012-07-31 09:07:28,539 [17] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 629.881393702645 
2012-07-31 09:07:28,542 [9] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 8779.17681696586 
2012-07-31 09:07:28,544 [4] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 8779.17681696586 
2012-07-31 09:07:28,544 [7] DEBUG Microsoft.ServiceModel.Samples.CalculatorService - Leaving: Microsoft.ServiceModel.Samples.CalculatorService.Multiply(double, double) : 1587.54403419867 
+0

我真的很希望它那么简单。我已经尝试过这些技巧的每一个配置,没有任何东西似乎有所作为。只有一个线程被使用。 – Skyline 2012-07-31 12:08:14

+0

我不确定它是否使用仅使用一个线程的第三方DLL。 – Skyline 2012-07-31 12:10:50

+0

那么,你的服务是不是线程安全的开始。你在InitialiseThirdParty中有一个竞速条件。我会测试示例代码,如果我可以得到多个线程产卵。你的测试方法是什么?你怎么知道你只有一个线程? – Darek 2012-07-31 12:14:15

2

看来很可能是你的第三方COM组件是独立的线程,因此具有线程关联。如果是这样,将只有一个线程在COM组件中进行工作。

然而,许多.NET线程正在被服务实现使用,它们都将不得不排队使用特定的STA线程,这是唯一能够调用COM对象的线程。

+0

确实是正确的。我确信它是多线程的,但通过运行替换函数它现在是100%的第三方问题,感谢所有的快速反应,无论如何球员。看起来像一些奇特的步法,使用一些额外的核心可能需要:(。 – Skyline 2012-07-31 15:47:17

+0

分享花哨的步法,如果你可以...永远不会太晚了解一件或两件事。 – Darek 2012-08-01 01:30:14

0

问题是第三方DLL只是一个单线程的COM模型。我导致认为它是多线程的,但通过运行替代功能,现在它成为第三方的问题。无论如何,感谢所有人的快速反应。看起来像一些奇特的步法,可能需要使用一些额外的核心。我发送了一封电子邮件给公司,看他们是否有MT版本,但我对此表示怀疑。再次感谢。

+0

如果您的问题得到解决,请将其标记为已回答。 – ErnieL 2012-08-01 20:39:16