IList vs array performance observation (.NET 2.0)
-
I was wanted to share some performance observations after fiddling around with arrays and
IList<type>
. Since e.g. adouble[]
a array automatically implementsIList<double>
in .NET 2.0 I can conveniently acceptIList<double>
as argument for any method without also needing an overload fordouble[]
. However, after some quick testing it seems a performance penalty is involved using theIList
interface! I used this small program to compare the options:using System; using System.Collections.Generic; using System.Text; namespace TestListVsArray { class Program { static void Main(string[] args) { double[] a = new double[10000]; for (int i = 0; i < 3; i++) { TestA(a); TestB(a); TestC(a); TestD(a); Console.WriteLine(); } } private static void TestA(IList a) { DateTime start = DateTime.Now; double x = 0d; for (int j = 0; j < 1000; j++) { for (int i = 0; i < a.Count; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestB(IList a) { DateTime start = DateTime.Now; double x = 0d; int n = a.Count; for (int j = 0; j < 1000; j++) { for (int i = 0; i < n; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestC(double[] a) { DateTime start = DateTime.Now; double x = 0d; for (int j = 0; j < 1000; j++) { for (int i = 0; i < a.Length; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestD(double[] a) { DateTime start = DateTime.Now; double x = 0d; int n = a.Length; for (int j = 0; j < 1000; j++) { for (int i = 0; i < n; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } } }
Output on my machine was -
I was wanted to share some performance observations after fiddling around with arrays and
IList<type>
. Since e.g. adouble[]
a array automatically implementsIList<double>
in .NET 2.0 I can conveniently acceptIList<double>
as argument for any method without also needing an overload fordouble[]
. However, after some quick testing it seems a performance penalty is involved using theIList
interface! I used this small program to compare the options:using System; using System.Collections.Generic; using System.Text; namespace TestListVsArray { class Program { static void Main(string[] args) { double[] a = new double[10000]; for (int i = 0; i < 3; i++) { TestA(a); TestB(a); TestC(a); TestD(a); Console.WriteLine(); } } private static void TestA(IList a) { DateTime start = DateTime.Now; double x = 0d; for (int j = 0; j < 1000; j++) { for (int i = 0; i < a.Count; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestB(IList a) { DateTime start = DateTime.Now; double x = 0d; int n = a.Count; for (int j = 0; j < 1000; j++) { for (int i = 0; i < n; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestC(double[] a) { DateTime start = DateTime.Now; double x = 0d; for (int j = 0; j < 1000; j++) { for (int i = 0; i < a.Length; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } private static void TestD(double[] a) { DateTime start = DateTime.Now; double x = 0d; int n = a.Length; for (int j = 0; j < 1000; j++) { for (int i = 0; i < n; i++) { x += a[i]; } } Console.WriteLine("{0}, {1}", DateTime.Now - start, x); } } }
Output on my machine wasOf course there will be a performance penalty for using a collection over an array. Even though with generics you can easily implement strongy typed collections (avoiding casting and boxing unboxing), the collections in fact use arrays. They provide you with more flexibility than an array (like you don't need to know the number of elements and they can grow as needed) but basically what it does is array operations. There are some ways you can improve performance, if you know the number of items you can setup the MaximumLenght property of your collection. Also, both with arrays and collections, whenever you try to access a member, the CLR will perform a bound check. but if you access it in a for loop, where you expressely use the .Count, or .Lenght property, the compiler is smart enough to detect that and won't do bound checks with a considerable performance gain (in long running loops). for example suppose you have an array a and you want to iteract. you can do it like this: int limit = a.Lenght; for (int i = 0; i < limit; i++) { } this will do a bound check for each iteraction. if you do for (int i=0; i < a.Lenght; i++) { } this boundcheck will not be performed.
-
Of course there will be a performance penalty for using a collection over an array. Even though with generics you can easily implement strongy typed collections (avoiding casting and boxing unboxing), the collections in fact use arrays. They provide you with more flexibility than an array (like you don't need to know the number of elements and they can grow as needed) but basically what it does is array operations. There are some ways you can improve performance, if you know the number of items you can setup the MaximumLenght property of your collection. Also, both with arrays and collections, whenever you try to access a member, the CLR will perform a bound check. but if you access it in a for loop, where you expressely use the .Count, or .Lenght property, the compiler is smart enough to detect that and won't do bound checks with a considerable performance gain (in long running loops). for example suppose you have an array a and you want to iteract. you can do it like this: int limit = a.Lenght; for (int i = 0; i < limit; i++) { } this will do a bound check for each iteraction. if you do for (int i=0; i < a.Lenght; i++) { } this boundcheck will not be performed.
The point is that I'm using a typesafe array in any case, not one of the collection flavors. I was just testing out which interface to the typesafe array was quickest. I would have hoped the difference between normal array access and access through
IList<double>
was minimal, but apparantly it isn't. :^) Also there seems no performance difference in practise between doing (see measurement results above): int limit = a.Lenght;for (int i = 0; i < limit; i++) { }
andfor (int i=0; i < a.Lenght; i++) { }
Maybe the compiler is smart enough here to optimize the limit variable away... Wout -
The point is that I'm using a typesafe array in any case, not one of the collection flavors. I was just testing out which interface to the typesafe array was quickest. I would have hoped the difference between normal array access and access through
IList<double>
was minimal, but apparantly it isn't. :^) Also there seems no performance difference in practise between doing (see measurement results above): int limit = a.Lenght;for (int i = 0; i < limit; i++) { }
andfor (int i=0; i < a.Lenght; i++) { }
Maybe the compiler is smart enough here to optimize the limit variable away... Woutwout de zeeuw wrote:
Maybe the compiler is smart enough here to optimize the limit variable away...
I'm not 100% sure but can't
a.Length
change inside the loop? So therefore the compiler can't optimize it unless it analyses the whole loop, and I'm guessing that the problems that could occur if it did would outweight the speed advantage. Ed -
wout de zeeuw wrote:
Maybe the compiler is smart enough here to optimize the limit variable away...
I'm not 100% sure but can't
a.Length
change inside the loop? So therefore the compiler can't optimize it unless it analyses the whole loop, and I'm guessing that the problems that could occur if it did would outweight the speed advantage. EdIt can indeed (just tested :-))! So beats me why the two options are equally fast. Wout
-
It can indeed (just tested :-))! So beats me why the two options are equally fast. Wout
Because they're both accessing the same type of variable. The a.Length one is simply a property wrapper around an int so in effect they're doing the same thing and hopefully JIT will optimize away the property call if it's just a wrapper, but I'm not so sure :rolleyes: Ed