WCF 服务是否使用多个线程来处理传入请求?

发布于 2025-01-06 06:29:18 字数 3684 浏览 1 评论 0原文

如何确保 WCF 服务使用 ThreadPool 中的线程来处理传入消息?

目前简单的方法调用,如“return null;”处理另一个请求大约需要 45 秒

这是我注释服务类的方式:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public partial class MyService : IMyService {
...
}

但是当我在任务管理器中观察进程时,它似乎正在使用恒定数量的线程。即使在负载下。


public ActionResult SelectDatabase(string param)
        {
            if (!String.IsNullOrEmpty(param))
            {
            try
            {
                MyServicece svc = new MyService();
                Database[] dbsArray = svc.GetDatabases(param);
                if (depsArray != null)
                    ViewData["depsArray"] = depsArray;

                return View();
            }
            catch (Exception exc)
            {
                // log here                
                return ActionUnavailable();
            }
        }

这是我的服务行为:

<?xml version="1.0"?>
<configuration>
  <runtime>

  </runtime>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="100" />
    </connectionManagement>
  </system.net>
  <system.serviceModel>
    <diagnostics performanceCounters="Default" />
    <bindings>      
      <netTcpBinding>
        <binding sendTimeout="00:02:00" receiveTimeout="00:02:00" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <security mode="None">           
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CrossDomainServiceBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyService.MyServiceBehavior">
          <serviceThrottling maxConcurrentCalls="100"   maxConcurrentInstances="100" maxConcurrentSessions="100" />
          <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="MyService.MyServiceBehavior" name="MyService.MyService">
        <endpoint address="MyService" binding="netTcpBinding" contract="AService.IAServ"  isSystemEndpoint="false" />
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
      </service>
      <service behaviorConfiguration="MyService.MyServiceBehavior" name="MyService.MyServiceAdmin">
        <endpoint address="MyServiceAdmin" binding="netTcpBinding" contract="MyService.IMyServiceAdmin"  isSystemEndpoint="false" />
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />        
      </service>
    </services>
  </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

这是我创建服务实例的方式:

ServiceHost myserviceHost = new ServiceHost(typeof(MyService), new Uri(String.Format("net.tcp://{0}/", _bindAddress)));
            myserviceHost.Open();
            Console.WriteLine(myserviceHost.BaseAddresses[0]);

How can I ensure that a WCF service uses threads from a ThreadPool to process incoming messages?

At the moment simple method invocation like 'return null;' takes about 45 seconds while another requests are processing

Here is how I have annotated my service class:

[ServiceBehavior(ConcurrencyMode = ConcurrencyMode.Multiple, InstanceContextMode = InstanceContextMode.Single)]
    public partial class MyService : IMyService {
...
}

But when I'm watching the process in task manager it seems to be using a constant number of threads. Even under load.


public ActionResult SelectDatabase(string param)
        {
            if (!String.IsNullOrEmpty(param))
            {
            try
            {
                MyServicece svc = new MyService();
                Database[] dbsArray = svc.GetDatabases(param);
                if (depsArray != null)
                    ViewData["depsArray"] = depsArray;

                return View();
            }
            catch (Exception exc)
            {
                // log here                
                return ActionUnavailable();
            }
        }

Here is my service behavior:

<?xml version="1.0"?>
<configuration>
  <runtime>

  </runtime>
  <system.net>
    <connectionManagement>
      <add address="*" maxconnection="100" />
    </connectionManagement>
  </system.net>
  <system.serviceModel>
    <diagnostics performanceCounters="Default" />
    <bindings>      
      <netTcpBinding>
        <binding sendTimeout="00:02:00" receiveTimeout="00:02:00" maxBufferSize="2147483647" maxReceivedMessageSize="2147483647" maxBufferPoolSize="2147483647">
          <security mode="None">           
          </security>
        </binding>
      </netTcpBinding>
    </bindings>
    <serviceHostingEnvironment aspNetCompatibilityEnabled="true"/>
    <behaviors>
      <endpointBehaviors>
        <behavior name="CrossDomainServiceBehavior">
          <webHttp />
        </behavior>
      </endpointBehaviors>
      <serviceBehaviors>
        <behavior name="MyService.MyServiceBehavior">
          <serviceThrottling maxConcurrentCalls="100"   maxConcurrentInstances="100" maxConcurrentSessions="100" />
          <dataContractSerializer maxItemsInObjectGraph="2147483646"/>
          <serviceMetadata httpGetEnabled="false" />
          <serviceDebug includeExceptionDetailInFaults="true" />
        </behavior>
      </serviceBehaviors>
    </behaviors>
    <services>
      <service behaviorConfiguration="MyService.MyServiceBehavior" name="MyService.MyService">
        <endpoint address="MyService" binding="netTcpBinding" contract="AService.IAServ"  isSystemEndpoint="false" />
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />
      </service>
      <service behaviorConfiguration="MyService.MyServiceBehavior" name="MyService.MyServiceAdmin">
        <endpoint address="MyServiceAdmin" binding="netTcpBinding" contract="MyService.IMyServiceAdmin"  isSystemEndpoint="false" />
        <endpoint address="mex" binding="mexTcpBinding" contract="IMetadataExchange" />        
      </service>
    </services>
  </system.serviceModel>
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0"/></startup></configuration>

Here is how I create service instance:

ServiceHost myserviceHost = new ServiceHost(typeof(MyService), new Uri(String.Format("net.tcp://{0}/", _bindAddress)));
            myserviceHost.Open();
            Console.WriteLine(myserviceHost.BaseAddresses[0]);

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

鱼窥荷 2025-01-13 06:29:18

InstanceContextMode 和 ConcurrencyMode 是独立的概念,但具有一定程度的相互作用 - 我不久前在博客中对此进行了深入讨论

WCF 调用是在 IO 线程池上处理的线程。假设您还没有执行诸如 ConcurrencyMode.SingleInstanceContextMode.Single 之类的操作,这些操作将序列化对服务的每个调用,线程池管理器将尝试将线程数平衡到工作率。

如果并发请求的数量可以由 5 个线程提供服务,那么这就是它将使用的数量。您可能会发现线程池可以跟上您可以看到的线程数量的工作速率。您可以非常高兴地使用比内核更多的线程,因为只要线程不纯粹受 CPU 限制,操作系统就可以在先前运行的线程启动 IO 时通过将线程切换到 CPU 来获得吞吐量。如果 CPU 完全耗尽,那么线程池管理器的启发式方法将使其不愿向线程池中添加更多线程。

但是,还有另外两个潜在问题:

  1. 基于会话的绑定可能会在客户端阻塞,而存在以下情况:通过同一代理的多个并发出站请求。您没有说明如何生成多个请求,因此这可能是一个问题;
  2. 您可能还会看到限制,在 .NET 4 之前,默认最大并发请求数为 16,默认并发会话数为 10。这些值已在 .NET 4 中提高,但您没有说明是哪个版本您正在使用的 .NET

InstanceContextMode and ConcurrencyMode are separate concepts but which have a level of interplay - I blogged about this in some depth a while back

WCF calls are processed on IO threadpool threads. Assuming you haven't done something like ConcurrencyMode.Single, InstanceContextMode.Single which will serialize every call into the service the threadpool manager will try to balance the number of threads to the rate of work.

If the number of concurrent requests can be serviced by 5 threads then that's how many it will use. You may be seeing that the threadpool can keep up with the rate of work with the number of threads you can see. You can quite happily use more threads than cores with effect because, as long as the threads are not purely CPU bound, the OS can gain throughput by switching threads onto the CPU when the previously running thread starts IO. If the CPU is completely max'd out then the heuristics of the threadpool manager will make it reticent to add more threads into the thread pool

However, there are another couple of potential issues:

  1. Session based bindings can block on the client side while there are multiple concurrent outbound requests through the same proxy. You don;t say how you are generating the multiple requests so this may be an issue;
  2. You may also be seeing throttling kicking in as, prior to .NET 4 the default max number of concurrent requests was 16 and default number of concurrent sessions was 10. These values have been raised in .NET 4 but you don't say which version of .NET you are using
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文