by
Paul Mendoza
1/31/2010
Here are some general suggestions for working with .NET that will help when writing high performance .NET code where milliseconds matter.
1. ArrayList is slower than List<>
2. List<> and an array have the same performance if the list's initial capacity is set to an appropriate size when the list is created.
If the list doesn't have an initial capacity set then it will create an array of 1 size. Then when a second item is added to the list it'll allocate a new array of size 2 and move the points from array 1 to array 2. Then after 2 each time it runs out of space it'll create a new array and double the size of the new array.
List<int> x = new List<int>(); <--- Bad
List<int> y = new List<int>(1000); <-Good
3. Lamba and LINQ expressions tend to be slower than running a for loop with if statements. If you find your code having performance issues always look at any place where you use a lamda or linq to object expressions because they may be running 2X - 5X slower than a for loop would in most cases.
Bad:
var x = from p in people where p.Name == "John" select p;
Good
List<Person> foundPeople = new List<Person>(20);
for(int i = 0; i < people.Count(); i++)
{
if(person.Name == "John")
foundPeople.Add(person);
}
The reason for this performance concern is that for the LINQ statement it has to perform some extra steps for each comparison. From what I understand the cost in the LINQ statement above that is has to do some type reflection in order to determine how the comparisons should operate.
There are ways to get your LINQ to operate fast though and this page explains the ways to do it. Since you can never be totally sure what LINQ-To-Objects is doing I tend to go with what I know over what I hope LINQ-To-Objects is doing.
4. Use Dictionary.TryGetValue instead of checking for the key and then pulling the value out by index.
Dictionary<int, string> dict = new Dictionary<int, string>();
dict.Add(1, "Paul");
dict.Add(445, "John");
Bad
string foundName;
if (dict.ContainsKey(445))
{
foundName = dict[445];
}
Good
string foundName;
if (!dict.TryGetValue(445, out foundName))
{
throw new Exception("Failed to find the index in the dictionary.");
}
5. RAM is the new hard drive so access it as little as possible. You can iterate over a list of objects and never actually access the data that composes the objects from RAM. A value doesn't generally get pulled from RAM unless it's needed.
List<Person> persons = (from f in Enumerable.Range(0, 10000)
select new Person()
{
Age = new Random().Next(12, 75),
Weight = new Random().Next(100, 250)
}).ToList();
// There is no slow memory access because it only loops over the pointers in the array.
for (int i = 0; i < persons.Count; i++)
{
Person person = persons[i];
}
// There is memory access here because the values that composed the object had to be retrieved from RAM.
for (int i = 0; i < persons.Count; i++)
{
Person person = persons[i];
int multiple = person.Weight * person.Age;
}
Also, there are multiple levels of being in RAM. L1 and L2 both sit on the CPU but there is very little of it. L1 takes 1 to 3 ticks to pull data from. L2 takes between 10 - 20 and L3 and standard RAM takes between 100 - 300.
Tags:
Categories: