[en] New fast remoting channel

Topics: Technical Support
Coordinator
Apr 1, 2012 at 6:34 PM
Edited Apr 26, 2012 at 11:19 AM

Disclaimer

This post was an April Fool's joke. NullChannel is not a real communication channel because it only works for senders and receivers of the same AppDomain. NullChannel is used for unit tests and profiling.

Hi,

I've just finished work on the new remoting channel which turned out to be quite fast.
Here is a screnshot of the benchmark run on my laptop:

Important numbers are all yellow (the less the better).
I'm going to check in the channel source code in an hour or so. 

Here is a complete source code of the benchmark I've used:

// csc bench.cs /r:Zyan.Communication.dll /debug

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Remoting.Channels.Tcp;
using System.Text;
using System.Threading.Tasks;
using Zyan.Communication.Protocols.Null;
using Hashtable = System.Collections.Hashtable;

namespace Benchmarks
{
  public interface IEcho
  {
    string Echo(string message);
  }

  public class EchoService : MarshalByRefObject, IEcho
  {
    public string Echo(string message)
    {
      return "echoed " + message;
    }
  }

  class Program
  {
    static void Main(string[] args)
    {
      const int iterations = 10000;

      RunBenchmark(new TcpChannelSetup(8080), iterations);
      RunBenchmark(new IpcChannelSetup("8765"), iterations);
      RunBenchmark(new NullChannelSetup(8192), iterations);

      Console.ReadLine();
    }

    static void RunBenchmark(IChannelSetup setup, int iterations)
    {
      var echo = new EchoService();
      var url = setup.Marshal(echo);
      var proxy = Activator.GetObject(typeof(IEcho), url) as IEcho;

      var defaultColor = Console.ForegroundColor;
      Console.WriteLine("==================================");
      Console.ForegroundColor = ConsoleColor.White;
      Console.WriteLine("Testing channel: {0}", setup.Name);
      Console.ForegroundColor = defaultColor;
      Console.WriteLine("EchoService url: {0}", url);
      Console.WriteLine("Result = {0}", proxy.Echo("Test"));
      Console.WriteLine("Running {0} iterations...", iterations);

      var sw = new Stopwatch();
      sw.Start();

      for (int i = 0; i < iterations; i++)
      {
        var result = proxy.Echo("Dummy");
      }

      sw.Stop();
      Console.ForegroundColor = ConsoleColor.Yellow;
      Console.WriteLine("Elapsed: {0} ms", sw.ElapsedMilliseconds);
      Console.WriteLine("Iteration time: {0} ms", (decimal)sw.ElapsedMilliseconds / iterations);
      Console.ForegroundColor = defaultColor;
    }
  }

  public interface IChannelSetup
  {
    string Name { get; }

    string Marshal(MarshalByRefObject obj);
  }

  public class TcpChannelSetup : IChannelSetup
  {
    public TcpChannelSetup(int port)
    {
      BaseUri = "tcp://localhost:" + port;
      var tcpServer = new TcpChannel(port);
      ChannelServices.RegisterChannel(tcpServer, false);
    }

    public string Name { get { return "TcpChannel"; } }

    private string BaseUri { get; set; }

    public string Marshal(MarshalByRefObject obj)
    {
      return BaseUri + RemotingServices.Marshal(obj).URI;
    }
  }

  public class IpcChannelSetup : IChannelSetup
  {
    public IpcChannelSetup(string port)
    {
      BaseUri = "ipc://" + port;
      var ipcServer = new IpcChannel(port);
      ChannelServices.RegisterChannel(ipcServer, false);
    }

    public string Name { get { return "IpcChannel"; } }

    private string BaseUri { get; set; }

    public string Marshal(MarshalByRefObject obj)
    {
      return BaseUri + RemotingServices.Marshal(obj).URI;
    }
  }

  public class NullChannelSetup : IChannelSetup
  {
    public NullChannelSetup(int port)
    {
      BaseUri = "null://localhost:" + port;
      var nullServer = new NullChannel("localhost:" + port);
      ChannelServices.RegisterChannel(nullServer, false);
    }

    public string Name { get { return "NullChannel"; } }

    private string BaseUri { get; set; }

    public string Marshal(MarshalByRefObject obj)
    {
      return BaseUri + RemotingServices.Marshal(obj).URI;
    }
  }
}
Coordinator
Apr 25, 2012 at 11:06 PM

Hi yallie,

Fine work. This will speed up unit tests.

Sorry for my late response. I've got very much work these days.

Coordinator
Apr 26, 2012 at 11:10 AM
Edited Apr 26, 2012 at 11:17 AM

Hi Rainbird,

that's ok, I'm busy too :)

The primary use for NullChannel is profiling.

Tuning Zyan pipeline performance using real communication channels is hardly possible because most time is spent in data transfer. NullChannes removes serialization and data transfer parts of the process, so we can easily measure Zyan's own numbers (message dispatch, invocation, event wiring, etc) in a real-life conditions.