Подтвердить что ты не робот

WCF против .Net Remoting

согласно этой статье, 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 в Single/Multiple;

но результаты одинаковы.

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

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

Спасибо заранее.

EDIT:

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

Первый тест выглядит следующим образом (Wcf test):

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 test):

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 работает быстрее. Тесты выполнялись за пределами отладчика.

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

4b9b3361

Ответ 1

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

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) Скомпилируйте его в режиме деблокирования и запустите его вне отладчика.

вот мой вывод enter image description here

Ответ 2

Если в дополнение к коду 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();
}

Ответы: enter image description here

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

Ответ 3

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

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

Не стоит сомневаться в превосходной производительности WCF для Inter-Process Communication.

Ответ 4

Wcf: 261,03 ms.
Wcf: 247,02 ms.
Wcf: 236,02 ms.
Wcf: 235,02 ms.
Wcf: 236,02 ms.

WCF NetNamedPipeBinding done. Avg : 243,02

Wcf: 508,05 ms.
Wcf: 467,05 ms.
Wcf: 484,05 ms.
Wcf: 458,05 ms.
Wcf: 458,05 ms.

WCF NetTcpBinding done. Avg : 475,05

Remoting: 35,00 ms.
Remoting: 58,01 ms.
Remoting: 35,00 ms.
Remoting: 35,00 ms.
Remoting: 34,00 ms.

Remoting done. Avg : 39,40