Blogs

Intelligent Design

Plasma, Dog Plasma: Generics vs. Objects

I came across an interesting quote from Tony Northrup regarding .net Generics:

 

 “I haven’t been able to reproduce the performance benefits of generics; however, according to Microsoft, generics are faster than using casting.  In practice, casting proved to be several times faster than using a generic.  However, you probably won't notice performance differences in your applications.”

 

Crazy Mixed up Pup

That reminded me of a 1954 cartoon called "Crazy Mixed Up Pup."  There was a Doctor who was given a couple bottles of plasma but couldn't figure out which to use on the dog and which to use on the man - pure genius. While I hope I am never faced with the decision of which bottle of plasma to wire up to dog or man, I often face the struggle of pulling out the right tool for a given need.    

 

For instance, .net has several different types of collections, not to mention generic collections introduced in 2.0, and others introduced by the community.  Let's face it, our tool bags are getting bigger, more robust - what do we do when we're introduced to things like Tony's discovery?

 

I chose to put together a little project to see if I could reproduce his findings and dig out the right tool...

1.       Created a console application

2.       Then 2 classes

a.       Object with two public members that where of type System.Object

b.      Generic with two public members that were generic types

using System;

using System.Collections.Generic;

using System.Text;

 

namespace ObjectVSGenerics {

    class Program {

        static void Main(string[] args) {

            RunTest(Console.ReadKey().Key);

            Console.ReadLine();

        }

 

        private static void RunTest(System.ConsoleKey key) {

            Int64 start = DateTime.Now.Ticks;

            for (int i = 0; i <= 1000000; i++) {

                if (key == ConsoleKey.O) {

                    Obj o = new Obj(1, 1);

                    int objInt = o.sum();//(int)o.obj1 + (int)o.obj2;

                } else if (key == ConsoleKey.G) {

                    Gen<int, int> g = new Gen<int, int>(1, 1);

                    int genInt = g.t + g.u;

                }

            }

            Int64 processingSeconds = (DateTime.Now.Ticks - start) / TimeSpan.TicksPerMillisecond;

            Console.WriteLine(" Process time in Milliseconds " + key.ToString() + ": " + (processingSeconds).ToString());

 

            Console.Write("Enter another: ");

            RunTest(Console.ReadKey().Key);

 

        }

 

    }

}

 

This is what I found:

Build / Framework

Generic mean exec time

Object mean exec time

% Efficiency

Debug .net 2.0

32ms

77ms

58% (Generic)

Debug .net 3.0

33ms

78ms

57% (Generic)

Debug .net 3.5

33ms

80ms

59% (Generic)

Release .net 2.0

15ms

64ms

76.5% (Generic)

Release .net 3.0

15ms

58ms

74% (Generic)

Release .net 3.5

15ms

57ms

74% (Generic)

 

Now, while I was not able to reproduce Tony’s findings and the scenario above was not a “real world” scenario (looping and instantiating an object or generic 1 million times in a given execution) I was able to conclude a few things:

 

·         The efficiency of the generic was higher than the object, and the efficiency of both were higher when executing Release code.  It makes total sense why a release build would be faster, especially regarding recursion (the framework is less aggressive about cleaning up resources in debug code, plus other optimizations).  However, why did the object stay close to the same execution mean and the generic become roughly 50% faster?

o   Check out this post by the C# team.  Basically this improvement is because the actual implementation is created at runtime. So when I create Gen<int, int> the JIT will see if it has previously been compiled and if it has will reuse it.  Secondly the Object implementation will always require boxing and unboxing of the value type int – that simply will not change, Release or not.

·         In this book Tony points out that a really good reason to use Generics is simply because they are type-safe.  Meaning that during compilation if a value you’re providing to your generic does not match the instantiated instance’s definition the compiler will error.  Generic code is only valid if it will compile every possible instance of the generic.

·         Finally, if you notice in the code above I created a method in the Object class to encapsulate the “sum” functionality.  Normally, you probably would not do this because when dealing with objects - you’re already running the risk of no type safety during runtime.  But to make a point – Generics cannot perform this sort of encapsulation; operators cannot be used as logic mechanisms.  When generic code is compiled it maintains its “generic-ness.” Therefore anything that would explicitly require a certain type will not compile.

 

The bottom-line is “real-world” forces you to use all of the tools in your tool bag, not just the cool ones.  We love adopting new technologies at Fellowship Technologies; we have to ride the razor’s edge to be able to evaluate and use the best that is out there so that we can build the best.

 

Generics seem to have a pretty significant advantage over objects and casting - it's a tool, I think, that has the possibility of make some solid, clean, and fast code.

 

--nick

Published Tuesday, December 04, 2007 6:36 AM by FTProductDev

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

No Comments

Leave a Comment

(required) 
(optional)
(required) 
Submit