Posted by: Talha | January 5, 2007

Collections Versus Generics in .NET

A pretty common task these days at work is migration and upgrading of older 1.1 framework code to the 2.0 framework. Some of the code is really straight forward to port to for example the System.Management Namespace based classes. However to leverage the new features of 2.0 a few changes must be made.

For anyone developing in .Net 2.0, Generics are definitely a great tool, allowing cleaner and more type-safe code. I was interested in how the use of Microsoft’s provided Generic classes in System.Collections.Generics performed relative to their non-generic alternatives.

I am often running into a question of whether or not I should bother changing out liberal use of the Systems.Collections classes in older code to use Generics. So I ran some tests….

Probably the most common collection used in pre-2.0 code is the ArrayList, so in these test I have compared the System.Collections.ArrayList class to the System.Collections.Generic.List class.

I created a c# console app in Visual Studio 2005, that ran a set of common operations against the two collections.The Complete code listing can be found at the end of the post.

I did a worst-case load for both generics and collections, letting the collection dynamically resize for random integer insertion, which is followed by a sort, and a traversal using the Contains() method. All of the items are 32bit Integers.

The test for Arraylist is exactly the same as the List test, with the obvious exception of the collection declaration. I ran the series of operations against the two collections with increasing item counts, and programatically timed them.

Result Output:

Size: 10000
Time taken by Collection: 15.6042 ms
Time taken by Generic: 0.002 ms

Size: 100000
Time taken by Collection: 187.2504 ms
Time taken by Generic: 15.6042 ms

Size: 250000
Time taken by Collection: 546.147 ms
Time taken by Generic: 62.4168 ms

Size: 500000
Time taken by Collection: 1263.9402 ms
Time taken by Generic: 218.4588 ms

It’s pretty clear who the winner is here. The Generic.List collection comes out substantially ahead of the ArrayList.

Not only is the Generic class faster, but it appears to scale substantially more linearly than the ArrayList, and handles the 10 million items in <1 second, compared to the 21+ seconds of the ArrayList.

From running a few more tests, I learnt that the real bottleneck on the Arraylist was during sorting and traversing the list. Each item is stored as an object, so it must be typed runtime, and then compared for sorting/searching. On the other side, the Generic List had all its items typed compile time, which saves alot of workload during sorting and searching.

So the first thing that comes to my mind, was that perhaps the collection logic was improved for the List, and it was dynamically resizing in a smarter fashion, which helped give it such a substantial speed increase. So I ran an interesting test…. I modified my code to use a List<object> instead of List<int>, so in theory, it would perform just as the ArrayList unless some other collection logic had changed.

The results were surprising. A List<object> performed within 5 ticks of ArrayList on any number of items.

This confirms that the performance gain of Generic Collections is entirely due to dropping the Object wrapper, and ridding us from the need to use Reflection on each object. So in conclusion, I can’t imagine wherein you would EVER want to use an Arraylist or SortedList in your .Net 2.0 code.

Happy coding.

using System;
using System.Collections;
using System.Collections.Generic;

namespace GenericCollectionComparison
{
internal class Program
{
public static int Length = 100000; //Int32.MaxValue;
private ArrayList arrayList;
private List genericList;
public static DateTime startTime;
public static DateTime endTime;
public static TimeSpan timeSpan;
public Random randomNumber = new Random();

public void fillCollection()
{
arrayList = new ArrayList();

for (int i = 0; i < Length; i++)
{
arrayList.Add(randomNumber.Next());
}

arrayList.Sort();
arrayList.Contains(randomNumber.Next());
}

public void fillGenerics()
{
genericList = new List();

for (int i = 0; i < Length; i++)
{
genericList.Add(randomNumber.Next());
}

genericList.Sort();
genericList.Contains(randomNumber.Next());
}

private void Run()
{
Console.Out.WriteLine(“Size: ” + Length);
startTime = DateTime.Now;
fillCollection();
endTime = DateTime.Now;
timeSpan = endTime.Subtract(startTime);
Console.Out.WriteLine(“Time taken by Collection: ” + timeSpan.TotalMilliseconds + ” ms”);

startTime = DateTime.Now;
fillGenerics();
endTime = DateTime.Now;
timeSpan = endTime.Subtract(startTime);
Console.Out.WriteLine(“Time taken by Generic: ” + timeSpan.TotalMilliseconds + ” ms”);

Console.WriteLine(“”);
}

private static void Main()
{
Program program = new Program();
for (int i = 10000; i < Int32.MaxValue; i = i + 10000)
{
Length = i;
program.Run();
}
}
}
}


Responses

  1. Hi

    Thanks for such a nice code. It took only a minute to understand why we should use Generics.List.

    Thanks a lot

  2. Dear Talha ,
    how are you ? ……. It was nice to see your blog

    Keep up the good work

    http://jafferpatel.blogspot.com


Leave a response

Your response:

Categories