WCF против удаленного взаимодействия .Net

согласно этой статье, WCF с именованными каналами - лучший выбор для IPC, и это примерно На 25% быстрее, чем .Net Remoting.

У меня есть следующий код, который сравнивает WCF с именованными каналами с .Net Remoting:

[ServiceContract]
internal interface IRemote
{
    [OperationContract]
    string Hello(string name);
}

[ServiceBehavior]
internal class Remote : MarshalByRefObject, IRemote
{
    public string Hello(string name)
    {
        return string.Format("Hello, {0}!", name);
    }
}

class Program
{
    private const int Iterations = 5000;

    static void Main(string[] args)
    {
        TestWcf(Iterations);
        TestRemoting(Iterations);

        TestWcf(Iterations);
        TestRemoting(Iterations);

        TestWcf(Iterations);
        TestRemoting(Iterations);

        Console.ReadKey();
    }

    private static void TestRemoting(int iterations)
    {
        var domain = AppDomain.CreateDomain("TestDomain");

        var proxy =
            (IRemote)
            domain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, "ConsoleApplication6.Remote");

        Console.WriteLine("Remoting: {0} ms.", Test(proxy, iterations));
    }

    private static void TestWcf(int iterations)
    {
        var address = "net.pipe://localhost/test";

        var host = new ServiceHost(typeof (Remote));
        host.AddServiceEndpoint(typeof (IRemote), new NetNamedPipeBinding(), address);
        host.Open();

        var proxy = ChannelFactory<IRemote>.CreateChannel(new NetNamedPipeBinding(), new EndpointAddress(address));

        Console.WriteLine("Wcf: {0} ms.", Test(proxy, iterations));

        host.Close();
    }

    private static double Test(IRemote proxy, int iterations)
    {
        var start = DateTime.Now;

        for (var i = 0; i < iterations; i++)
        {
            proxy.Hello("Sergey");
        }

        var stop = DateTime.Now;

        return (stop - start).TotalMilliseconds;
    }
}

A получил следующие результаты за 5000 итераций:

Wcf: 14143 ms.
Remoting: 2232 ms.
Wcf: 14289 ms.
Remoting: 2130 ms.
Wcf: 14126 ms.
Remoting: 2112 ms.

В этом тесте Wcf примерно в 7 раз медленнее, чем .Net Remoting.

Я пытался:

  • установите режим безопасности None;
  • установите InstanceContextMode на Single / PerCall;
  • установите для параметра ConcurrencyMode значение "Один / несколько";

но результаты те же.

Кто-нибудь знает, что я делаю не так? Почему WCF такой медленный?

Есть ли способ ускорить этот код?

Заранее спасибо.

РЕДАКТИРОВАТЬ:

Я немного изменил тест. Контракт такой же.

Первый тест выглядит так (тест Wcf):

class Program
{
    private const int Iterations = 5000;

    static void Main(string[] args)
    {
        var address = "net.pipe://localhost/test";

        var host = new ServiceHost(typeof(Remote));
        host.AddServiceEndpoint(typeof(IRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), address);
        host.Open();

        var proxy = ChannelFactory<IRemote>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), new EndpointAddress(address));

        TestWcf(proxy, Iterations);
        TestWcf(proxy, Iterations);
        TestWcf(proxy, Iterations);
        TestWcf(proxy, Iterations);
        TestWcf(proxy, Iterations);

        Console.ReadKey();

        host.Close();
    }

    private static void TestWcf(IRemote proxy, int iterations)
    {
        var start = DateTime.Now;

        for (var i = 0; i < iterations; i++)
        {
            proxy.Hello("Sergey");
        }

        var stop = DateTime.Now;

        Console.WriteLine("Wcf: {0} ms.", (stop - start).TotalMilliseconds);
    }
}

Вот результаты:

Wcf: 2564 ms.
Wcf: 1026 ms.
Wcf: 986 ms.
Wcf: 990 ms.
Wcf: 992 ms.

Второй тест выглядит так (тест .Net Remoting):

class Program
{
    private const int Iterations = 5000;

    static void Main(string[] args)
    {
        var domain = AppDomain.CreateDomain("TestDomain");

        var proxy =
            (IRemote)
            domain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, "ConsoleApplication6.Remote");

        TestRemoting(proxy, Iterations);
        TestRemoting(proxy, Iterations);
        TestRemoting(proxy, Iterations);
        TestRemoting(proxy, Iterations);
        TestRemoting(proxy, Iterations);

        Console.ReadKey();
    }

    private static void TestRemoting(IRemote proxy, int iterations)
    {
        var start = DateTime.Now;

        for (var i = 0; i < iterations; i++)
        {
            proxy.Hello("Sergey");
        }

        var stop = DateTime.Now;

        Console.WriteLine("Remoting: {0} ms.", (stop - start).TotalMilliseconds);
    }
}

Вот результаты:

Remoting: 261 ms.
Remoting: 224 ms.
Remoting: 252 ms.
Remoting: 243 ms.
Remoting: 234 ms.

Как видите, .Net Remoting снова стал быстрее. Тесты проводились вне отладчика.

Почему это так?


person Sergey    schedule 08.11.2011    source источник
comment
Вы можете предоставить свой файл конфигурации?   -  person villecoder    schedule 08.11.2011
comment
villecoder: Конфиги не использую. Привязка, конечная точка и поведение задаются в коде.   -  person Sergey    schedule 08.11.2011


Ответы (3)


Отладчики не являются реальной мерой, когда я пытаюсь сравнить производительность, вот что я сделал и получил WCF, выталкивающий удаленное взаимодействие с кольца;)

1) Также изменил ваш тест, чтобы запускать его из той же программы / exe

  namespace ConsoleApplication6
{
  [ServiceContract]
  internal interface IRemote
  {
    [OperationContract]
    string Hello(string name);
  }

  [ServiceBehavior]
  internal class Remote : MarshalByRefObject, IRemote
  {
    public string Hello(string name)
    {
      return string.Format("Hello, {0}!", name);
    }
  }

  class Program
  {
    private const int Iterations = 5000;

    static void Main(string[] p)
    {
      TestWcf();
      TestRemoting();
    }


    static void TestWcf()
    {
      var address = "net.pipe://localhost/test";

      var host = new ServiceHost(typeof(Remote));
      host.AddServiceEndpoint(typeof(IRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), address);
      host.Open();

      var proxy = ChannelFactory<IRemote>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), new EndpointAddress(address));

      TestWcf(proxy, Iterations);
      TestWcf(proxy, Iterations);
      TestWcf(proxy, Iterations);
      TestWcf(proxy, Iterations);
      TestWcf(proxy, Iterations);

      Console.WriteLine("WCF done");

      host.Close();
    }

    private static void TestWcf(IRemote proxy, int iterations)
    {
      var start = DateTime.Now;

      for (var i = 0; i < iterations; i++)
      {
        proxy.Hello("Sergey");
      }

      var stop = DateTime.Now;

      Console.WriteLine("Wcf: {0} ms.", (stop - start).TotalMilliseconds);
    }

    static void TestRemoting()
    {
      var domain = AppDomain.CreateDomain("TestDomain");

      var proxy =
          (IRemote)
          domain.CreateInstanceFromAndUnwrap(Assembly.GetEntryAssembly().Location, "ConsoleApplication6.Remote");

      TestRemoting(proxy, Iterations);
      TestRemoting(proxy, Iterations);
      TestRemoting(proxy, Iterations);
      TestRemoting(proxy, Iterations);
      TestRemoting(proxy, Iterations);
      Console.WriteLine("Remoting done");
      Console.ReadKey();
    }

    private static void TestRemoting(IRemote proxy, int iterations)
    {
      var start = DateTime.Now;

      for (var i = 0; i < iterations; i++)
      {
        proxy.Hello("Sergey");
      }

      var stop = DateTime.Now;

      Console.WriteLine("Remoting: {0} ms.", (stop - start).TotalMilliseconds);
    }
  }

}

2) Скомпилируйте его в режиме выпуска и запустите вне отладчика.

вот мой результат введите описание изображения здесь

person Surjit Samra    schedule 08.11.2011
comment
Спасибо за замечания. Действительно, вне отладчика он работает быстрее. - person Sergey; 09.11.2011
comment
Я также понял из одного из моих предыдущих потоков SO, что если вы установите Тип сборки на Release, производительность также повысится. - person Vamsi; 10.12.2011

Если в дополнение к коду SSamra вы переместите создание своего хоста за пределы вашего теста WCF (поскольку, по моему мнению, вы должны создавать хост только один раз), вы можете получить еще более быстрые ответы:

static void Main(string[] args)
{
    var address = "net.pipe://localhost/test";

    host = new ServiceHost(typeof(Remote));
    host.AddServiceEndpoint(typeof(IRemote), new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), address);
    host.Open();

    proxy = ChannelFactory<IRemote>.CreateChannel(new NetNamedPipeBinding(NetNamedPipeSecurityMode.None), new EndpointAddress(address));

    TestWcf(Iterations);
    TestRemoting(Iterations);

    TestWcf(Iterations);
    TestRemoting(Iterations);

    TestWcf(Iterations);
    TestRemoting(Iterations);

    host.Close();

    Console.ReadKey();
}

Ответы: введите описание изображения здесь

Это показывает, что при такой настройке WCF в процессе значительно быстрее, чем удаленное взаимодействие .Net!

person Tad Donaghe    schedule 08.11.2011
comment
Я получаю почти идентичные ответы, если переношу создание прокси-сервера Remoting в основную программу. - person Tad Donaghe; 09.11.2011
comment
Замечательно! Но я обновил вопрос. Пожалуйста, посмотрите. - person Sergey; 09.11.2011

Статья MSDN, на которую вы ссылаетесь в начале своего вопроса, сравнивает удаленное взаимодействие с WCF NetNamedPipes как механизм IPC (что означает межпроцессное взаимодействие, а не внутрипроцессное взаимодействие). Ваш тестовый код сравнивает производительность связи в рамках одного и того же процесса.

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

Это не повод сомневаться в превосходной производительности WCF для межпроцессного взаимодействия.

person Chris Dickson    schedule 09.11.2011
comment
Мне кажется, что WCF - не лучший выбор для обмена данными между доменами приложений. - person Sergey; 10.11.2011