I have created a program (see below) that compares the tcp and http remoting
channels. The results are very interesting and lead me to ask several
questions:

1) Why is the tcp channel so much faster than the http channel? 3 times
faster seems too good to be true.

2) Why is the [OneWay] method over the tcp channel slower than a method
without [OneWay]? But using the http channel the [OneWay] method is 15%
faster than non [OneWay].

3) Why is the remoting across machines faster than just across process on
the same machine? The difference is small, but I am running it on a dual
processor machine so it should be able to keep up with my 100Mbps (2 half
duplex hubs between the machines) network.

4) Why is the [OneWay] method over the tcp channel so slow? 86.313 seconds!
The regular method call only takes 4 seconds and running the same thing over
the http channel only takes 10.297. There seems to be something very wrong
with that, but I am able to repeat it again and again.


The test program can be run in either client or server mode (one of each is
required). The client can connect either locally or remotely to the server.
One object type is exposed as a singleton over the tcp and http channels.
Both channels are set to use the BinaryFormatter (the http channel defaults
to the SoapFormatter, which is obviously slower). The client tests each
object in turn, it times batches of 5000 tests, calling different methods:

void RegularMethod(string) takes a string, examines it, and returns void.
string RegularMethodReturn(string) takes a string, examines it, and returns
a unique string.
[OneWay] void OneWayMethod(string) takes a string, examines it, and returns
void. It has the OneWayAttribute set.

The client times the batch of 5000 calls and displays the time taken in
seconds. The result of the RegularMethodReturn is stored in an ArrayList to
ensure that it really does return the results. This would appear to add very
minimal overhead.

The hardware used to run the test was a pair of dual P3 533MHz running
Win2000 and .NET runtime 1.0 retail (+SP2). The network connection was a
100Mbps half duplex.


Running with the client and server on the same machine gives the following
results:

>TestChannels.exe -client

Connecting to localhost
Testing TCP Channel
Done with RegularMethod batch! 4.047
Done with RegularMethodReturn batch! 4.157
Done with OneWay batch! 4.281
DONE Testing TCP Channel

Testing HTTP Channel
Done with RegularMethod batch! 14.579
Done with RegularMethodReturn batch! 15.046
Done with OneWay batch! 12.282
DONE Testing HTTP Channel



Running with the client and server on separate machines gives the following
results:

>TestChannels.exe -client=isis

Connecting to isis
Testing TCP Channel
Done with RegularMethod batch! 4
Done with RegularMethodReturn batch! 4.234
Done with OneWay batch! 86.313
DONE Testing TCP Channel

Testing HTTP Channel
Done with RegularMethod batch! 13.281
Done with RegularMethodReturn batch! 13.657
Done with OneWay batch! 10.297
DONE Testing HTTP Channel




The code for the test program is:

using System;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Channels;

namespace TestChannels
{
 class Class1
 {
  [MTAThread] static void Main(string[] args)
  {
   if (args.Length == 1)
   {
    if (string.Compare(args[0], "-client", true) == 0)
    {
     Client("localhost"); return;
    }
    else if (args[0].StartsWith("-client="))
    {
     Client(args[0].Substring(args[0].IndexOf('=')+1)); return;
    }
    else if (string.Compare(args[0], "-server", true) == 0)
    {
     Server(); return;
    }
   }
   Console.WriteLine("Argument required [-client|-server]");
  }

  // Start in Client mode. Connect to the server and run the Test
  static void Client(string host)
  {
   Console.WriteLine("Connecting to "+host);

   ChannelServices.RegisterChannel(new
System.Runtime.Remoting.Channels.Tcp.TcpClientChannel("", new
BinaryClientFormatterSinkProvider()));
   ChannelServices.RegisterChannel(new
System.Runtime.Remoting.Channels.Http.HttpClientChannel("", new
BinaryClientFormatterSinkProvider()));

   TestObject tcpObject =
(TestObject)Activator.GetObject(typeof(TestObject),
"tcp://"+host+":2525/TestObject.rem");
   TestObject httpObject =
(TestObject)Activator.GetObject(typeof(TestObject),
"http://"+host+":8585/TestObject.rem";);

   Console.WriteLine("Testing TCP Channel");
   ClientTest(tcpObject);
   Console.WriteLine("DONE Testing TCP Channel\n");

   Console.WriteLine("Testing HTTP Channel");
   ClientTest(httpObject);
   Console.WriteLine("DONE Testing HTTP Channel\n");
  }

  const int WARMUP_SIZE=1000;
  const int BATCH_SIZE=5000;

  // Test the performace of the TestObject
  static void ClientTest(TestObject testObject)
  {
   // Warm up
   for(int item=0; item<WARMUP_SIZE; item++)
   {
    testObject.RegularMethod("Batch"+item);
    string strRet = testObject.RegularMethodReturn("Batch"+item);
    testObject.OneWayMethod("Batch"+item);
   }

   int start;
   int end;

   // Batch Reqular Methods
   start = Environment.TickCount;

   for(int item=0; item<BATCH_SIZE; item++)
   {
    testObject.RegularMethod("Batch"+item);
   }
   end = Environment.TickCount;

   Console.WriteLine("Done with RegularMethod batch! {0}",
TimeSpan.FromMilliseconds(end - start).TotalSeconds);
   testObject.RegularMethod("BatchEnd");

   // Batch Reqular Methods
   start = Environment.TickCount;

   System.Collections.ArrayList list = new
System.Collections.ArrayList(BATCH_SIZE);
   for(int item=0; item<BATCH_SIZE; item++)
   {
    string strRet = testObject.RegularMethodReturn("Batch"+item);
    list.Add(strRet);
   }
   end = Environment.TickCount;

   Console.WriteLine("Done with RegularMethodReturn batch! {0}",
TimeSpan.FromMilliseconds(end - start).TotalSeconds);
   testObject.RegularMethodReturn("BatchEnd");

   // Batch One Way Methods
   start = Environment.TickCount;

   for(int item=0; item<BATCH_SIZE; item++)
   {
    testObject.OneWayMethod("Batch"+item);
   }
   end = Environment.TickCount;

   Console.WriteLine("Done with OneWay batch! {0}",
TimeSpan.FromMilliseconds(end - start).TotalSeconds);
   testObject.OneWayMethod("BatchEnd");
  }

  // Start in server mode. Serve the TestObject via tcp and http channels
  static void Server()
  {
   try
   {
    ChannelServices.RegisterChannel(new
System.Runtime.Remoting.Channels.Tcp.TcpServerChannel("", 2525, new
BinaryServerFormatterSinkProvider()));
    ChannelServices.RegisterChannel(new
System.Runtime.Remoting.Channels.Http.HttpServerChannel("", 8585, new
BinaryServerFormatterSinkProvider()));

    RemotingConfiguration.RegisterWellKnownServiceType(typeof(TestObject),
"TestObject.rem", WellKnownObjectMode.Singleton);
   }
   catch(Exception e)
   {
    Console.WriteLine("Exception = " + e);
    return;
   }
   System.Console.WriteLine("Hit <enter> to exit server...");
   System.Console.ReadLine();
  }
 }

 public class TestObject : MarshalByRefObject
 {
  public int pingCount = 0;

  [System.Runtime.Remoting.Messaging.OneWay] public void OneWayMethod(String
s)
  {
   if (s.StartsWith("BatchEnd"))
   {
    Console.WriteLine("OneWayMethod {0}", s);
   }
  }
  public String RegularMethodReturn(String s)
  {
   if (s.StartsWith("BatchEnd"))
   {
    Console.WriteLine("RegularMethod {0}", s);
   }
   return "foo" + (++pingCount);
  }
  public void RegularMethod(String s)
  {
   if (s.StartsWith("BatchEnd"))
   {
    Console.WriteLine("RegularMethod {0}", s);
   }
  }
 }
}

THE END

You can read messages from the Advanced DOTNET archive, unsubscribe from Advanced 
DOTNET, or
subscribe to other DevelopMentor lists at http://discuss.develop.com.

Reply via email to