为什么第一个WCF客户端调用速度慢?

时间:2012-06-02 04:39:29

标签: .net wcf performance .net-4.0 basichttpbinding

我试图弄清楚为什么客户端应用程序启动后第一次WCF调用与第二次调用相比要花费更多时间。

我做了什么测试:

  1. 实现了简单的自托管WCF服务器和控制台客户端。
  2. 服务器已预热 - 我在运行测试之前运行它并多次调用方法。
  3. 绑定为basicHttpBinding,以减少网络和安全开销。
  4. 测试方案 - 启动控制台客户端应用程序,连续进行两次相同的WCF服务调用。
  5. 在我的测试中,我看到第一次通话约为700毫秒,第二次通话约为3毫秒。

    几乎一秒似乎是JIT编译器的时间太多了。我会接受,如果那个时间用于初始化一些复杂的基础设施,如实体框架中的ObjectContext,但我的代码非常简单,代理类已经编译。

    我也试过netNamedPipeBinding绑定。结果证明模式 - 第一次调用需要~800 ms,第二次调用需要~8 ms。

    如果有人能解释为什么第一次服务电话花费这么多时间,我们将不胜感激。

    在Win 7 64位中测试。

    我的实施如下。

    合同:

    [ServiceContract]
    public interface ICounter
    {
            [OperationContract]
            int Add(int num);
    }
    

    服务实施:

    public class CounterService: ICounter
    {
            private int _value = 0;
    
            public int Add(int num)
            {
                _value += num;
                Console.WriteLine("Method Add called with argument {0}. Method  returned {1}", num, _value);
                return _value;
            }
    }
    

    服务器实施:

    class Program
    {
        static void Main(string[] args)
        {
            Uri baseAddress = new Uri("http://localhost:8080/Service");
    
            // Create the ServiceHost.
            using (ServiceHost host = new ServiceHost(typeof(CounterService), baseAddress))
            {
                host.Open();
    
                Console.WriteLine("The service is ready at {0}", baseAddress);
                Console.WriteLine("Press <Enter> to stop the service.");
                Console.ReadLine();
    
                // Close the ServiceHost.
                host.Close();
            }
        }
    }
    

    服务器配置:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <services>
          <service name="Server.CounterService">
            <endpoint address="base" binding="basicHttpBinding" name="baseDefault"
              contract="Contract.ICounter" />
            <endpoint address="net.pipe://localhost/Service/netNamedPipe"
              binding="netNamedPipeBinding" name="netNamedPipeDefault" contract="Contract.ICounter" />
            <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange" />
          </service>
        </services>
        <behaviors>
          <serviceBehaviors>
            <behavior name="">
              <serviceMetadata httpGetEnabled="true" />
            </behavior>
          </serviceBehaviors>
        </behaviors>
      </system.serviceModel>
    </configuration>
    

    客户端实施(CounterProxy从服务引用生成):

    Stopwatch stopWatch = new Stopwatch();
    stopWatch.Start();
    
    using (var proxy = new CounterProxy.CounterClient(_endpointConfigurationName))
    {
        output = proxy.Add(1);
    }
    
    stopWatch.Stop();
    // Get the elapsed time as a TimeSpan value.
    TimeSpan ts = stopWatch.Elapsed;
    

    包含连续两次调用的代码的函数。

    客户端配置:

    <?xml version="1.0" encoding="utf-8" ?>
    <configuration>
      <system.serviceModel>
        <client>
          <endpoint address="http://localhost:8080/Service/base" binding="basicHttpBinding"
              contract="CounterProxy.ICounter"
              name="baseDefault" />
        </client>
      </system.serviceModel>
    </configuration>
    

4 个答案:

答案 0 :(得分:7)

通常第一次调用需要更多时间,因为在该调用中Channel Factory被实例化并准备好进行通信并且花费时间。创建的Channel Factory将被缓存并在后续调用中重用,因此时间会更短。

http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd

答案 1 :(得分:2)

我有类似的问题。那么我们实际上做了什么,我们编写了调用WCF服务的服务 每隔一段时间。我知道这不是一个优雅的解决方案,但它正在发挥作用。

答案 2 :(得分:2)

如果您在15秒内不太频繁地拨打WCF服务(我们发现需要在我们的应用程序中等待大约20秒),这个Microsoft博客似乎可以解释您的问题:http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx

该文章还链接到此条目,其中提到了对SetMinThreads()的修复,这似乎也是一个有问题的问题: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx

答案 3 :(得分:2)

当我第一次创建我的服务代理实例时,我看到了30秒范围内的延迟,我知道它必须与某种网络超时有关。

最后对我来说实际上是检查证书撤销列表被公司代理(yay Websense)阻止或挫败,如下所示:WCF service startup too slow? Have you thought to CRL check?

供将来参考,如果链接失效,可以将以下内容添加到客户端配置中:

<configuration>
  <runtime>
    <generatePublisherEvidence enabled=“false”/>
  </runtime>
</configuration>