Почему первый вызов WCF-клиента замедляется?
Я пытаюсь понять, почему первый вызов WCF после запуска клиентского приложения занимает гораздо больше времени по сравнению со вторым.
Что я сделал, чтобы проверить это:
- Реализован простой сам сервер WCF и консольный клиент.
- Сервер разогревается. Я запускаю его и вызываю метод несколько раз перед запуском теста.
- Связывание
basicHttpBinding
уменьшает затраты на сеть и безопасность.
- Сценарий тестирования - запустите консольное клиентское приложение, выполнив два одинаковых вызова службы WCF в строке.
В моих тестах я вижу ~ 700 миллисекунд для первого вызова и ~ 3 миллисекунды для второго вызова.
Кажется, что для JIT-компилятора слишком много времени. Я бы согласился, если это время используется для инициализации некоторой сложной инфраструктуры, такой как ObjectContext
в Entity Framework, но мой код очень прост и прокси-классы уже скомпилированы.
Я также пробовал привязку netNamedPipeBinding
. Результат доказывает шаблон - первый вызов занимает ~ 800 мс, второй вызов занимает ~ 8 мс.
Поймите, если кто-нибудь сможет объяснить, почему первый вызов службы занимает так много времени.
Протестировано в Win 7 64 бит.
Моя реализация ниже.
Contract:
[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>
Ответы
Ответ 1
Обычно первый вызов занимает больше времени, потому что в этом вызове Channel Factory
создается и готовится к сообщению, и это требует времени. Созданный Channel Factory
будет кэшироваться и повторно использоваться в последующих вызовах, поэтому время будет меньше.
http://social.msdn.microsoft.com/Forums/en/wcf/thread/43f89088-546b-46b0-adf8-214deb1741bd
Ответ 2
У меня схожая проблема. Итак, что мы на самом деле сделали, мы написали сервис, который вызывает службу WCF
за некоторый интервал. Я знаю, что это не элегантное решение, но оно работает.
Ответ 3
Если вы звоните в ваш 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
Статья также ссылается на эту запись, в которой упоминается исправление для SetMinThreads(), которое также представляется важной проблемой:
http://blogs.msdn.com/b/wenlong/archive/2010/02/11/why-are-wcf-responses-slow-and-setminthreads-does-not-work.aspx
Ответ 4
Я видел задержки в диапазоне 30 секунд, когда я впервые создавал экземпляр прокси-сервера службы, который, как я знал, должен быть связан с каким-то сетевым таймаутом.
В конце концов, это было фактически проверка списка отзыва сертификатов, который был заблокирован или расстроен корпоративным прокси (yay Websense), как указано здесь: Запуск службы WCF слишком медленный? Вы считали, что CRL проверяет?.
Для справок в будущем и в случае, если ссылка остыла, она сводилась к добавлению следующего в конфигурацию клиента:
<configuration>
<runtime>
<generatePublisherEvidence enabled="false"/>
</runtime>
</configuration>