Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Performance cost of type comparisons

I am decoding comms messages from a binary stream. I create message objects of varying types depending on what messages have arrived. They all derive from a base CommsMessage type. All fine and dandy.

Elsewhere in my code I need to react to these messages, so I need to know what type of message it is.

Currently I am doing:

void ProcessIncomingMessage(CommsMessage msg)
{
    if (msg is MessageType1)
        return ProcessMessageType1(msg as MessageType1);

    if (msg is MessageType2)
        return ProcessMessageType2(msg as MessageType2);

    //etc
}

I am wondering what the performance cost of comparing these types are, and whether I should include a MessageType property in the base class instead. Then I could do:

void ProcessIncomingMessage(CommsMessage msg)
{
    switch (msg.MessageType)
    {
         case MessageType.Type1:  return ProcessMessageType1(msg as MessageType1);
         case MessageType.Type2:  return ProcessMessageType2(msg as MessageType2);

         //etc
    }
}

Yes, this is premature optimisation, and I'm probably worrying over insignificant details, but I'm the kind of coder who likes to know what's going on under the covers and so was wondering the performance differences between the two. I guess I have a prejudice against type comparisons from my C++ background where RTTI introduced an overhead, and just wondered if .Net had any similarities.

like image 847
GazTheDestroyer Avatar asked Jan 20 '12 09:01

GazTheDestroyer


3 Answers

Have you considered eliminating the type casts?

I'm guessing you've considered that putting the virtual method on the Message type itself would break a layering abstraction (e.g. you might want a clean separation of the processing of the message from the message itself). Maybe consider the visitor pattern. This'll allow you to separate out the Message class from the processing of the Message itself.

If you have something of this structure.

abstract class CommsMessage {}
class Message1 : CommsMessage {}
class Message2 : CommsMessage {}

You could refactor to

abstract class CommsMessage 
{ 
    public abstract void Visit(CommsMessageVisitor v);
}

class Message1 : CommsMessage 
{
    public void Visit(CommsMessageVisitor v) { v.Accept(this); }
}

class Message2 : CommsMessage 
{
    public void Visit(CommsMessageVisitor v) { v.Accept(this); }
}

interface CommsMessageVisitor 
{
   void Accept(Message1 msg1);
   void Accept(Message1 msg2);
}

At this point, you've eliminated the type-casts. You can now rewrite your code as

void ProcessIncomingMessage(CommsMessage msg) 
{
  new MyVisitor().Visit(msg);
}

class MyVisitor : CommsMessageVisitor
{
    void Accept(Message1 msg1) { ProcessMessageType1(msg1); }
    void Accept(Message1 msg2) { ProcessMessageType2(msg2); }
}

Of course there might be reasons you can't do this, but it's always nicer to avoid type casts if you can!

like image 164
Jeff Foster Avatar answered Sep 23 '22 14:09

Jeff Foster


Note that your code is not syntactically valid, as the return types are void, but anyway.

Well, I'm not too sure about the performance difference of the two alternatives you show. However, at least FxCop would "suggest" the following instead of your first solution:

void ProcessIncomingMessage(CommsMessage msg)
{
  MessageType1 msg1 = msg as MessageType1;

  if (msg1 != null)
  {
      ProcessMessageType1(msg1);
      return;
  }

  MessageType2 msg2 = msg as MessageType2;

  if (msg2 != null)
  {
      ProcessMessageType2(msg2);
      return;
  }


  //etc
}

Of course, there are other issues involved here like maintainability, comprehensibility, etc. Possibly it would be better to provide an "virtual void ProcessMessage()" on your "CommsMessage" class, that you overwrite for each "MessageType". Then let the CLR work for you.

public class CommsMessage
{
    public virtual void ProcessMessage()
    {
       // Common stuff.
    }
}

public class MessageType1 : CommsMessage
{
   public override void ProcessMessage()
   {
      base.ProcessMessage();
      // type 1 specific stuff.
   }
}

// ...

void ProcessIncomingMessage(CommsMessage msg)
{
   msg.ProcessMessage();
}

Arguably, you can call msg.ProcessMessage() directly, where you now call ProcessIncomingMessage, if there is nothing else in there to do.

like image 35
Christian.K Avatar answered Sep 21 '22 14:09

Christian.K


To add to the excellent answers above:

In performance profiling I have noticed that using is followed by as actually resulted in lower performance than a single as followed by null check. Don't expect the compiler to automatically optimise anything. You are right to assume that in messaging code (or otherwise performance critical sections) that designing for speed is of paramount importance.

By far the fastest cast is a static cast which outperforms as i.e. var message = (SpecificType)baseMessage will outperform var message = baseMessage as SpecificType. This is a point of interest only as a static cast cannot help you in your case.

As two answers have already mentioned performing the above in a polymorphic fashion using a design pattern could be the best solution, as it only adds a virtual method call. Extracting the common method to an abstract class (or common method signature to interface) is by far the most elegant solution. There is an overhead of calling a virtual method but this can be mitigated by marking the specific methods on derived types using the sealed keyword.

Finally use generics where possible to eliminate casts as generic methods are a compile-time optimisation as opposed to run-time casting.

Best regards,

like image 29
Dr. Andrew Burnett-Thompson Avatar answered Sep 23 '22 14:09

Dr. Andrew Burnett-Thompson