Почему первый вызов клиента WCF выполняется медленно?

Я пытаюсь понять, почему первый вызов WCF после запуска клиентского приложения занимает гораздо больше времени по сравнению со вторым.

Что я сделал для проверки:

  1. Реализовал простой собственный сервер WCF и консольный клиент.
  2. Сервер прогрет- я запускаю его и вызываю метод несколько раз перед запуском теста.
  3. Привязка — это basicHttpBindingдля снижения нагрузки на сеть и безопасность.
  4. Сценарий тестирования — запуск консольного клиентского приложения, выполнение двух одинаковых вызовов службы WCF подряд.

В моих тестах я вижу ~700 миллисекунд для первого вызова и ~3 миллисекунды для второго вызова.

Почти секунда кажется слишком большим временем для JIT-компилятора. Я бы согласился, если бы это время было использовано для инициализации какой-то сложной инфраструктуры, такой как ObjectContextв Entity Framework, но мой код очень прост, а прокси-классы уже скомпилированы.

Я также пробовал связывание netNamedPipeBinding. Результат подтверждает закономерность - первый вызов занимает ~800 мс, второй вызов занимает ~8 мс.

Буду признателен, если кто-нибудь объяснит, почему первый звонок в службу поддержки занимает так много времени.

Протестировано в 64-разрядной версии Win 7.

Моя реализация ниже.

Контракт:

[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>
14
задан marc_s 2 June 2012 в 08:12
поделиться