问题描述
我想弄清楚为什么客户端应用程序启动后的第一个 WCF 调用比第二个调用花费更多的时间.
I am trying to figure out why the first WCF call after client application start takes much more time comparing to second one.
我做了什么来测试:
- 实现了简单的自托管 WCF 服务器和控制台客户端.
- 服务器已预热 - 我运行它并在运行测试之前多次调用方法.
- 绑定是
basicHttpBinding
,以减少网络和安全开销. - 测试场景 - 启动控制台客户端应用程序,连续进行两次相同的 WCF 服务调用.
- 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
basicHttpBinding
to reduce network and security overhead. - Testing scenario - start console client app, making two identical WCF service calls in a row.
在我的测试中,我看到第一次调用约 700 毫秒,第二次调用约 3 毫秒.
In my tests I see ~700 milliseconds for first call and ~3 milliseconds for second call.
对于 JIT 编译器来说,几乎一秒钟似乎太长了.如果这段时间用于初始化一些复杂的基础结构,例如实体框架中的 ObjectContext
,我会接受,但我的代码非常简单,并且已经编译了代理类.
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 ObjectContext
in Entity Framework but my code is very simple and proxy classes are already compiled.
我也尝试过 netNamedPipeBinding
绑定.结果证明了模式 - 第一次调用需要约 800 毫秒,第二次调用需要约 8 毫秒.
I also tried netNamedPipeBinding
binding. Result proves pattern - first call takes ~800 ms, second call takes ~8 ms.
如果有人能解释为什么第一次服务电话需要这么多时间,我们将不胜感激.
Will appreciate if anybody can explain why the first service call takes so much time.
在 Win 7 64 位测试.
Tested in Win 7 64 bit.
我的实现如下.
合同:
[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
是从服务引用生成的):
Client Implementation (CounterProxy
is generated from service reference):
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.
客户端配置:
<?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>
推荐答案
通常第一次调用需要更多时间,因为在那个调用中 Channel Factory
被实例化并准备好进行通信,这会花费时间.创建的Channel Factory
将被缓存并在后续调用中重复使用,因此时间会更少.
Usually the first call takes more time because in that call the Channel Factory
is instantiated and prepared ready for the communication and that costs time. The created Channel Factory
will be cached and reused in subsequent calls and so the time will be less.
http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd
这篇关于为什么第一个 WCF 客户端调用很慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!