.net 为什么第一个 WCF 客户端调用很慢?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/10859832/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Why is the first WCF client call slow?
提问by Dmitry Harnitski
I am trying to figure out why the first WCF call after client application start takes much more time comparing to second one.
我试图弄清楚为什么客户端应用程序启动后的第一个 WCF 调用比第二个调用花费更多的时间。
What I did to test that:
我做了什么来测试:
- Implemented simple self hosted WCF Server and console client.
- Server IS warmed up- I run it and call method several times before running test.
- Binding is
basicHttpBindingto reduce network and security overhead. - Testing scenario - start console client app, making two identical WCF service calls in a row.
- 实现了简单的自托管 WCF 服务器和控制台客户端。
- 服务器已预热- 我运行它并在运行测试之前多次调用方法。
- 绑定是
basicHttpBinding为了减少网络和安全开销。 - 测试场景 - 启动控制台客户端应用程序,连续进行两个相同的 WCF 服务调用。
In my tests I see ~700 milliseconds for first call and ~3 milliseconds for second call.
在我的测试中,我看到第一次调用约 700 毫秒,第二次调用约 3 毫秒。
Almost a second seems to be too much time for JIT compiler. I would accept if that time is used to initialize some complicated infrastructure like ObjectContextin Entity Framework but my code is very simple and proxy classes are already compiled.
对于 JIT 编译器来说,几乎一秒钟似乎太长了。如果这段时间用于初始化一些复杂的基础结构(如ObjectContext实体框架),我会接受,但我的代码非常简单,并且已经编译了代理类。
I also tried netNamedPipeBindingbinding. Result proves pattern - first call takes ~800 ms, second call takes ~8 ms.
我也试过netNamedPipeBinding绑定。结果证明了模式 - 第一次调用需要约 800 毫秒,第二次调用需要约 8 毫秒。
Will appreciate if anybody can explain why the first service call takes so much time.
如果有人能解释为什么第一次服务电话需要这么多时间,我们将不胜感激。
Tested in Win 7 64 bit.
在 Win 7 64 位中测试。
My implementation is below.
我的实现如下。
Contract:
合同:
[ServiceContract]
public interface ICounter
{
[OperationContract]
int Add(int num);
}
Service Implementation:
服务实施:
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;
}
}
Server Implementation:
服务器实现:
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();
}
}
}
Server Configuration:
服务器配置:
<?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>
Client Implementation (CounterProxyis generated from service reference):
客户端实现(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;
Function that contains that code called two times in a row.
包含连续调用两次的代码的函数。
Client Configuration:
客户端配置:
<?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>
采纳答案by VJAI
Usually the first call takes more time because in that call the Channel Factoryis instantiated and prepared ready for the communication and that costs time. The created Channel Factorywill be cached and reused in subsequent calls and so the time will be less.
通常第一次调用需要更多时间,因为在该调用Channel Factory中实例化并为通信做好准备,这会花费时间。创建的Channel Factory将被缓存并在后续调用中重用,因此时间会更少。
http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd
http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd
回答by userx
If you are making calls to your WCF service less frequently than 15 seconds (we observed needing to wait about 20 seconds in our application), this Microsoft blog appears to explain your problem: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx
如果您调用 WCF 服务的频率低于 15 秒(我们观察到在我们的应用程序中需要等待大约 20 秒),这个 Microsoft 博客似乎可以解释您的问题:http: //blogs.msdn.com/b/wenlong /archive/2010/02/11/why-does-wcf-become-slow-after-being-idle-for-15-seconds.aspx
The article also links to this entry which mentions a fix for SetMinThreads() which also appears to be a contributing problem: http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx
该文章还链接到此条目,其中提到了 SetMinThreads() 的修复,这似乎也是一个促成问题:http: //blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are- wcf-responses-slow-and-setminthreads-does-not-work.aspx
回答by Shaun
I was seeing delays in the range of 30 seconds when I was first creating my service proxy instance which I knew must be related to some sort of network timeout.
当我第一次创建服务代理实例时,我看到延迟在 30 秒范围内,我知道这肯定与某种网络超时有关。
In the end for me it was actually checks for the Certificate Revocation List that were being blocked or frustrated by the corporate proxy (yay Websense) as highlighted here: WCF service startup too slow? Have you thought to CRL check?.
最后对我来说,它实际上是检查被公司代理 (yay Websense) 阻止或受阻的证书吊销列表,如下所示:WCF 服务启动太慢?你有没有想过 CRL 检查?.
For future reference and in case the link goes dead it came down to adding the following to the client config:
为了将来参考,如果链接失效,可以归结为将以下内容添加到客户端配置中:
<configuration>
<runtime>
<generatePublisherEvidence enabled=“false”/>
</runtime>
</configuration>
回答by Gregory Nozik
I have similar problem. So what we actually did, we wrote service that invoke WCF service per some interval. I know that it's not an elegant solution but it's working.
我有类似的问题。所以我们实际上做了什么,我们编写了每隔一段时间调用 WCF 服务的服务。我知道这不是一个优雅的解决方案,但它确实有效。

