Index Books FAQ Contact About Rod

# Title: Compare LINQ speeds for different approaches in C#

This example compares LINQ speeds while using LINQ in various ways.

To find the minimum and maximum X values in a List<Point>, the example Use LINQ to find a bounding box for a list of PointF in C# defines a LINQ query that selects the X coordinates from the list. I then uses the LINQ Min and Max extension methods on the query. (It repeats those steps to find the minimum and maximum Y values.)

When you click the Go button, this example compares that technique to a few others. The following code shows the first test.

Stopwatch watch = new Stopwatch(); // Find the minimum and maximum values in 2 queries. watch.Reset(); watch.Start(); int xmin = (from Point p in points select p.X).Min(); int xmax = (from Point p in points select p.X).Max(); watch.Stop(); txt2Queries.Text = watch.Elapsed.TotalSeconds.ToString("0.00") + " sec"; Refresh();

This code creates and starts a Stopwatch. It then uses two LINQ queries, both of which select the X coordinates from a list of random Point structures. The code uses the queries' Min and Max LINQ extension methods to get the minimum and maximum values. It finishes by displaying the elapsed time.

The following code shows the second test.

// Find the minimum and maximum values in 1 reused query. watch.Reset(); watch.Start(); var x_query = from Point p in points select p.X; xmin = x_query.Min(); xmax = x_query.Max(); watch.Stop(); txt1Query.Text = watch.Elapsed.TotalSeconds.ToString("0.00") + " sec"; Refresh();

This test creates a single query to select X values and then uses its Min and Max methods. If you look at the picture above, you'll see that this method has basically the same performances as the previous method.

The following code shows the third test.

// Find the minimum and maximum values with an array. watch.Reset(); watch.Start(); var arr_query = from Point p in points select p.X; int[] xs = arr_query.ToArray(); xmin = xs.Min(); xmax = xs.Max(); watch.Stop(); txtArray.Text = watch.Elapsed.TotalSeconds.ToString("0.00") + " sec"; Refresh();

This code creates a LINQ query as before. It calls the query's ToArray method to copy the X coordinates into an array. It then uses the array's Min and Max methods to find the smallest and largest values.

The idea here was that perhaps the previous tests wasted time building the list of X values twice. If you look at the picture above, you'll see that this method took considerably longer than the previous methods, so building the array explicitly didn't help.

The following code shows the fourth test.

// Find the minimum and maximum values with a loop. watch.Reset(); watch.Start(); xmin = points[0].X; xmax = xmin; for (int i = 1; i < points.Length; i++) { if (xmin > points[i].X) xmin = points[i].X; if (xmax < points[i].X) xmax = points[i].X; } watch.Stop(); txtLoop.Text = watch.Elapsed.TotalSeconds.ToString("0.00") + " sec"; Refresh();

This code finds the minimum and maximum values by looping through the array with a for loop. If you look at the picture, you'll see that this method took less than half as long as the fastest LINQ methods. This should be no surprise. You don't use LINQ because it's fast, you use it because it's easy. Writing the loops yourself is messier, but if you need the extra performance (and usually you don't), then it's worth it.

The following code shows the final test.

// Find the minimum and maximum values with a foreach loop. watch.Reset(); watch.Start(); xmin = points[0].X; xmax = xmin; foreach (Point pt in points) { if (xmin > pt.X) xmin = pt.X; if (xmax < pt.X) xmax = pt.X; } watch.Stop(); txtForeach.Text = watch.Elapsed.TotalSeconds.ToString("0.00") + " sec"; Refresh();

This code finds the minimum and maximum values by using a foreach loop. It takes about the same amount of time as the for loop.

The moral of the story is, use LINQ if it's convenient and you don't care too much about performance. If you really need every millisecond of performance, write your own loop.