I'm Keyvan Nayyeri, a 25 years old Ph.D. student at
the Computer Science department of
the University of Texas at San Antonio.
I'm also
a Software Architect and Developer and previously held a B.Sc.
degree in Applied Mathematics.
This is my blog where I publish content about various topics specifically Programming Languages and Compilers, Software
Engineering and Programming.
Generics were of one of main new features in .NET 2.0 languages. In .NET 1.x developers had to use System.Collections non-Generic collections to save their objects but no type checking were occurred for them. Therefore they had to do a type casting when they were retrieving their objects from collections.
Now that Microsoft introduced Generics as a type specific alternative for those old means, life is pretty easier for each developer. One of most important reasons to use Generics instead of non-Generic collections is performance.
As you don't need to cast an object as what you did when you read it from a collection such as ArrayList your performance will be improved.
Obviously each and every developer should try to use Generics in his code but what's the actual effect of using them on performance?
In this post I want to write some test codes with Generics and non-Generic collections then run them and use Visual Studio performance sessions to get some statistical information and compare these two new and old approaches to show you the influence of using Generics on performance.
Probably you already know doing a performance test on an abstract object which doesn't need any interaction with IO and database should avoid using these operations to give a good result.
So to have a correct comparison between Generics and non-Generic collections I'll create and add some objects to them then will retrieve these objects from them later.
To have a better result I'll put all above codes in some iterations while I'm running these codes. I also will use Visual Studio performance reports to log everything about functions I used in my code.
Finally I'll use Excel to analyze returned results from my reports.
These are some necessary definitions for parameters I'll use to analyze my performance reports and will refer to their names later in this post (rewritten from Visual Studio tooltips):
In this post I'll compare some real world common scenarios such as List<T> against ArrayList as well as Queue<T> against Queue.
ArrayList was one of common .NET 1.x objects. It can save a collection of objects regardless of their types. When you want to retrieve your objects, should cast them to original type.
List<T>is a Generic collection which is very similar to ArrayList and can be a good alternative for it. The main difference between List<T> and ArrayList is the first one is type specific and second is non-Generic. Note that in all situations you can't replace ArrayList with List<T> but in many cases it's possible and recommended.
I begin my test by creating a very simple Product class. This class has three properties:
public class Product
{
private int id;
public int ID
{
get { return id; }
set { id = value; }
}
private string serial;
public string Serial
{
get { return serial; }
set { serial = value; }
}
private string name;
public string Name
{
get { return name; }
set { name = value; }
}
}
Later I want to use object instances of this class in my code to add them to my collections. I write a simple method to generate some random values and use them to create instances of Product class and set their values then add them to a List<Product> and an ArrayList. Finally I'll call ListOfTMethod() and ListMethod() methods to iterate through these two collections to log their performance.
private void Process()
{
List<Product> List1 = new List<Product>();
ArrayList List2 = new ArrayList();
Random rand = new Random();
for (int i = 0; i < 10000; i++)
{
Product product = new Product();
int id = rand.Next(10000);
product.ID = id;
Guid guid = Guid.NewGuid();
product.Serial = guid.ToString();
product.Name = "Product #" + id.ToString();
List1.Add(product);
List2.Add(product);
}
ListOfTMethod(List1);
ArrayListMethod(List2);
}
It's time to write ListOfTMethod() and ListMethod() methods. These two methods help to log the performance of my collections. They simply get both collections and append string value of the properties contained in them and return final string value.
private void ListOfTMethod(List<Product> List)
{
foreach (Product product in List)
{
}
}
private void ArrayListMethod(ArrayList List)
{
foreach (Product product in List)
{
}
}
Now I run my code but before start running I create a performance session to log their performance during run.
After running the code everything is logged and I can export them to .CVS files and analyze them in Excel.
I open my file in Excel and remove unnecessary rows to keep only two rows that contain the information of my methods.
This is the information I got from my performance reports:
Obviously using Generics could improve my performance. The result above is just for a very simple small application with simple classes and iterations. As this process is just a very small part of a larger application this difference can have a larger effect on whole performance.
Queue is another member of System.Collections which has a new alternative in Generics. Queue is FIFO data structure and is one of key concepts of Data Structures and Algorithm Analysis.
This test is very similar to what I did for List and ArrayList. I add Product objects to Queue<Product> and a normal Queue and call two different methods for them.
private void Process()
{
Queue<Product> Queue1 = new Queue<Product>();
Queue Queue2 = new Queue();
Random rand = new Random();
for (int i = 0; i < 10000; i++)
{
Product product = new Product();
int id = rand.Next(10000);
product.ID = id;
Guid guid = Guid.NewGuid();
product.Serial = guid.ToString();
product.Name = "Product #" + id.ToString();
Queue1.Enqueue(product);
Queue2.Enqueue(product);
}
QueueOfTMethod(Queue1);
QueueMethod(Queue2);
}
This is the source code of QueueOfTMethod() and QueueMethod() methods:
private void QueueOfTMethod(Queue<Product> queue)
{
while (queue.Count > 0)
{
Product product = queue.Dequeue();
}
}
private void QueueMethod(Queue queue)
{
while (queue.Count > 0)
{
Product product = queue.Dequeue() as Product;
}
}
Result of performance reports is as follows:
You see the third diagram (Elapsed Inclusive Time) has a different result. But what's the reason? I guess the reason is hidden in the algorithms that should be used to perform some tasks on Queue data structure. If you do a same test on Stack data structure (which needs same kinds of algorithms), will get same result. Probably children functions of QueueOfTMethod() that will do some internal operations on Queue<Product> have more cost than their corresponding children functions in QueueMethod().
Use Generics to improve your performance. You saw their influence in my tests. In larger real world applications this influence is greater.
protected virtual void jaysonBlog {
Aug 21, 2006 2:45 PM
#
David Keaveny
Aug 21, 2006 5:18 PM
#
Keyvan Nayyeri
Aug 21, 2006 7:52 PM
#
You're absolutely right :-)
I had to use "non-Generic" instead of "strongly typed" collections in my introduction. The reason is maybe because I wrote it before my code.
However thanks for pointing it :-)
Jon Skeet
Aug 22, 2006 12:21 PM
#
Keyvan Nayyeri
Aug 22, 2006 2:50 PM
#
Technical Musings
Oct 01, 2007 2:19 PM
#
Manjula
Jun 18, 2009 6:40 AM
#
This site is Very simple Informatiove on Generis, please check this
Leave a Comment