クライアントアプリケーションの開始後の最初のWCF呼び出しが、2番目の呼び出しに比べてはるかに時間がかかる理由を理解しようとしています。
それをテストするために私がしたこと:
- シンプルなセルフホストのWCFサーバーとコンソールクライアントを実装しました。
- サーバーがウォームアップされています-テストを実行する前に、サーバーを実行してメソッドを数回呼び出します。
- バインディングは
basicHttpBinding
、ネットワークとセキュリティのオーバーヘッドを削減することです。 - テストシナリオ-コンソールクライアントアプリを起動し、2つの同一のWCFサービス呼び出しを続けて行います。
私のテストでは、最初の呼び出しで約700ミリ秒、2番目の呼び出しで約3ミリ秒が表示されます。
JITコンパイラにとっては1秒近く時間がかかりすぎるようです。その時間がEntityFrameworkのような複雑なインフラストラクチャの初期化に使用される場合は受け入れますObjectContext
が、私のコードは非常に単純で、プロキシクラスはすでにコンパイルされています。
netNamedPipeBinding
バインディングも試してみました。結果はパターンを証明します-最初の呼び出しには約800ミリ秒かかり、2番目の呼び出しには約8ミリ秒かかります。
最初のサービスコールに時間がかかる理由を誰かが説明できれば幸いです。
Win764ビットでテスト済み。
私の実装は以下のとおりです。
契約:
[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;
2回続けて呼び出されたコードを含む関数。
クライアント構成:
<?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>