WCF vs..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 значение Single / Multiple;
Но результаты те же самые. Кто-нибудь знает, что я делаю не так? Почему 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):

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

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

4 29

4 ответа:

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

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

Если, в дополнение к коду 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 remoting!

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

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

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

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