为什么第一次使用WCF客户端调用很慢?

16

我正在尝试弄清楚为什么客户端应用程序启动后的第一个WCF调用比第二个调用需要更多时间。

我用来测试的方法是:

  1. 实现了一个简单的自托管WCF服务器和控制台客户端。
  2. 已经预热好 - 我运行它并在运行测试之前调用了几次方法。
  3. 使用basicHttpBinding绑定,以减少网络和安全开销。
  4. 测试场景- 启动控制台客户端应用程序,在一行代码中进行两次相同的WCF服务调用。

在我的测试中,第一次调用时间大约为700毫秒,第二次调用时间为约3毫秒。

一秒钟似乎太长了,可能是由于JIT编译器导致的。如果这段时间用于初始化一些复杂的基础结构(如Entity Framework中的ObjectContext),我可以接受,但我的代码非常简单,代理类已经编译过了。

我也尝试了netNamedPipeBinding绑定,结果证明了这种模式-第一次调用需要约800毫秒,第二次调用需要约8毫秒。

如果有人能解释为什么第一个服务调用需要这么长时间,我将不胜感激。

在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>

可能是第一次加载/编译代理对象,XML序列化器等。如果您观察输出窗口,应该会看到类似于“已加载程序集x54fjfj3fj”的内容,这是一个已编译的WCF客户端。 - ta.speot.is
1
我归咎于安全检查和其他100个未知因素。涉及的二进制文件比部署服务中的要多得多。要调试服务,请在配置中使用跟踪器并访问日志,它们将显示每个步骤花费的确切时间(以毫秒为单位)。即使您已将所有内容设置为匿名,您也将看到类似身份验证、过滤器等的内容。 - user215054
4个回答

8

但是这个建议是针对客户端的,如果我理解正确的话。我们不能在服务端做些什么吗?要求每个客户端都这样做并不容易。 - Emil
1
看起来微软终于在这方面给予了一些控制权:https://msdn.microsoft.com/en-us/library/hh160401%28v=vs.110%29.aspx - userx

3
如果您对WCF服务的调用频率低于15秒(我们在应用程序中需要等待约20秒),那么这篇微软博客似乎可以解释您的问题: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

2
我第一次创建服务代理实例时,发现延迟约为30秒,我知道这一定与某种网络超时有关。
对我来说,最后实际上是证书吊销清单检查被公司代理(yay Websense)阻止或受挫,如此强调:WCF service startup too slow? Have you thought to CRL check?
供将来参考,以防链接失效,需要在客户端配置中添加以下内容:
<configuration>
  <runtime>
    <generatePublisherEvidence enabled=“false”/>
  </runtime>
</configuration>

2
在.NET Framework 4及更高版本中,此元素对程序集加载时间没有影响。有关更多信息,请参阅.NET Framework中的安全更改中的“安全策略简化”部分。https://msdn.microsoft.com/zh-cn/library/dd233103(v=vs.100).aspx(切换到.NET 4.0) - Ludwo

2
我有类似的问题。所以我们实际上编写了一个服务,定期调用WCF服务。我知道这不是一种优雅的解决方案,但它确实有效。

你有任何想法为什么会发生这种情况吗?似乎很多人都看到了,但我认识的人都不理解原因。谢谢回复。 - Dmitry Harnitski
2
看看这个,写得很好 http://www.codeproject.com/Tips/114132/WCF-First-Call-Slow - Nick
你使用了什么时间间隔?从我所看到的情况来看,缓存似乎与超时无关。但是少于1分钟。 - userx

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接