We are moving to .NET2.0 - and have noticed that .Contains() seems to be
around 20% slower under NET2, compared to NET1.1.
This code shows the issue:
static void Main(string[] args)
{
System.Collections.ArrayList list = new System.Collections.ArrayList();
//Setup code
//
//Add 10000 objects to a collection.
//Don't care what type the object is for the purposes of this
demonstration
for (int i=0; i<100000; i++)
{
list.Add(new EventArgs());
}
//We are going to find this object (intentially right at the end of the
list)
object objectToFind = list[99998];
//
// End setup code
// Timing code
//
long startT = Environment.TickCount;
//Find the object 1111 times in the collection
for (int j=0;j<1111;j++)
{
bool objectInList = list.Contains(objectToFind);
}
System.Console.WriteLine("Contains took "+(Environment.TickCount-startT)+"
(ms)");
System.Console.ReadLine();
}
Under NET1.1 I consistently get times in the order of 20% quicker than the
same code under NET2.
Has anyone else noticed this? Is there a way I can avoid whatever new code
is being executed in the bowels of the framework?
Thanks
Rob
Jon Skeet [C# MVP] - 12 Sep 2006 05:18 GMT
> We are moving to .NET2.0 - and have noticed that .Contains() seems to be
> around 20% slower under NET2, compared to NET1.1.
<snip>
> Has anyone else noticed this? Is there a way I can avoid whatever new code
> is being executed in the bowels of the framework?
I would suggest avoiding using ArrayList.Contains on pretty large
lists. Using a hashtable with a constant value (or a value equal to the
respective key) is likely to be far faster for checking inclusion than
a list. (You can always keep a list *as well* if you need ordering
etc.)

Signature
Jon Skeet - <skeet@pobox.com>
http://www.pobox.com/~skeet Blog: http://www.msmvps.com/jon.skeet
If replying to the group, please do not mail me too
William Stacey [MVP] - 14 Sep 2006 08:52 GMT
Looks like about the only change is an additional null test in the loop.
Hard to believe a single test would account for 20%, but maybe.
I think this fixes a bug so it is needed code.

Signature
William Stacey [MVP]
| We are moving to .NET2.0 - and have noticed that .Contains() seems to be
| around 20% slower under NET2, compared to NET1.1.
[quoted text clipped - 39 lines]
| Thanks
| Rob
Greg Young - 14 Sep 2006 15:08 GMT
I believe the default comparison is also a bit slower.
Cheers,
Greg
> Looks like about the only change is an additional null test in the loop.
> Hard to believe a single test would account for 20%, but maybe.
[quoted text clipped - 47 lines]
> | Thanks
> | Rob
William Stacey [MVP] - 14 Sep 2006 17:50 GMT
Hi Greg. "default comparison"? In the code, the only difference I see is 1
line with and added test for null.

Signature
William Stacey [MVP]
|I believe the default comparison is also a bit slower.
|
| Cheers,
Ben Voigt - 26 Oct 2006 18:44 GMT
> Looks like about the only change is an additional null test in the loop.
> Hard to believe a single test would account for 20%, but maybe.
> I think this fixes a bug so it is needed code.
There is definitely an unneeded test for null in the second loop in
ArrayList.Contains(item)
Equals is required to be commutative
(http://msdn2.microsoft.com/en-us/library/ms173147.aspx), so one can easily
call item.Equals since item has already been found to be non-null, instead
of on each array element, especially since Equals is required to test its
argument for null anyway.
Furthermore, it seems that List<T>.FindIndex(delegate (T x) { return
item.Equals(x); }) should be faster than List<T>.Contains(item) for the same
reason.
> | We are moving to .NET2.0 - and have noticed that .Contains() seems to be
> | around 20% slower under NET2, compared to NET1.1.
[quoted text clipped - 43 lines]
> | Thanks
> | Rob
Robert Hooker - 14 Sep 2006 17:09 GMT
Thanks all - for you replies. I'm happy enough that the 15%-20% slow-down is
at least experienced by others and its not me on crack.
Collectively, your replies have given me a few hints as to ways to improve
things. (Avoid .Contains were we can, and where we can't, I'll investigate
other Comparers)
Thanks again
Rob
> We are moving to .NET2.0 - and have noticed that .Contains() seems to be
> around 20% slower under NET2, compared to NET1.1.
[quoted text clipped - 39 lines]
> Thanks
> Rob
Chris Nahr - 14 Sep 2006 22:20 GMT
Rob, have you tried substituting List<T> for ArrayList? Perhaps the
implementation of that collection is a bit faster.
>Thanks all - for you replies. I'm happy enough that the 15%-20% slow-down is
>at least experienced by others and its not me on crack.
[quoted text clipped - 5 lines]
>Thanks again
>Rob

Signature
http://www.kynosarges.de
Robert Hooker - 18 Sep 2006 21:32 GMT
Strangely enough - List<T> "Contains" is measureably SLOWER (about 10%
slower) than ArrayList's "Contains".
Sigh...
> Rob, have you tried substituting List<T> for ArrayList? Perhaps the
> implementation of that collection is a bit faster.
[quoted text clipped - 9 lines]
>>Thanks again
>>Rob
Chris Nahr - 19 Sep 2006 08:39 GMT
Sorry about that, I should have checked the implementations first...
The algorithms look identical in Reflector but List<T>.Contains uses
an EqualityComparer<T> to check for identical elements while
ArrayList.Contains calls the usual Equals method. I suppose that
might account for the difference.
>Strangely enough - List<T> "Contains" is measureably SLOWER (about 10%
>slower) than ArrayList's "Contains".
>Sigh...
>

Signature
http://www.kynosarges.de