Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C# FindAll VS Where Speed

Anyone know any speed differences between Where and FindAll on List. I know Where is part of IEnumerable and FindAll is part of List, I'm just curious what's faster.

like image 333
Dested Avatar asked Feb 14 '10 05:02

Dested


2 Answers

The FindAll method of the List<T> class actually constructs a new list object, and adds results to it. The Where extension method for IEnumerable<T> will simply iterate over an existing list and yield an enumeration of the matching results without creating or adding anything (other than the enumerator itself.)

Given a small set, the two would likely perform comparably. However, given a larger set, Where should outperform FindAll, as the new List created to contain the results will have to dynamically grow to contain additional results. Memory usage of FindAll will also start to grow exponentially as the number of matching results increases, where as Where should have constant minimal memory usage (in and of itself...excluding whatever you do with the results.)

like image 154
jrista Avatar answered Sep 19 '22 12:09

jrista


FindAll is obviously slower than Where, because it needs to create a new list.

Anyway, I think you really should consider Jon Hanna comment - you'll probably need to do some operations on your results and list would be more useful than IEnumerable in many cases.

I wrote small test, just paste it in Console App project. It measures time/ticks of: function execution, operations on results collection(to get perf. of 'real' usage, and to be sure that compiler won't optimize unused data etc. - I'm new to C# and don't know how it works yet,sorry).

Notice: every measured function except WhereIENumerable() creates new List of elements. I might be doing something wrong, but clearly iterating IEnumerable takes much more time than iterating list.

using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Diagnostics;  namespace Tests {      public class Dummy     {         public int Val;         public Dummy(int val)         {             Val = val;         }     }     public class WhereOrFindAll     {         const int ElCount = 20000000;         const int FilterVal =1000;         const int MaxVal = 2000;         const bool CheckSum = true; // Checks sum of elements in list of resutls         static List<Dummy> list = new List<Dummy>();         public delegate void FuncToTest();          public static long TestTicks(FuncToTest function, string msg)         {             Stopwatch watch = new Stopwatch();             watch.Start();             function();             watch.Stop();             Console.Write("\r\n"+msg + "\t ticks: " + (watch.ElapsedTicks));             return watch.ElapsedTicks;         }         static void Check(List<Dummy> list)         {             if (!CheckSum) return;             Stopwatch watch = new Stopwatch();             watch.Start();              long res=0;             int count = list.Count;             for (int i = 0; i < count; i++)     res += list[i].Val;             for (int i = 0; i < count; i++)     res -= (long)(list[i].Val * 0.3);              watch.Stop();             Console.Write("\r\n\nCheck sum: " + res.ToString() + "\t iteration ticks: " + watch.ElapsedTicks);         }         static void Check(IEnumerable<Dummy> ieNumerable)         {             if (!CheckSum) return;             Stopwatch watch = new Stopwatch();             watch.Start();              IEnumerator<Dummy> ieNumerator = ieNumerable.GetEnumerator();             long res = 0;             while (ieNumerator.MoveNext())  res += ieNumerator.Current.Val;             ieNumerator=ieNumerable.GetEnumerator();             while (ieNumerator.MoveNext())  res -= (long)(ieNumerator.Current.Val * 0.3);              watch.Stop();             Console.Write("\r\n\nCheck sum: " + res.ToString() + "\t iteration ticks :" + watch.ElapsedTicks);         }         static void Generate()         {             if (list.Count > 0)                 return;             var rand = new Random();             for (int i = 0; i < ElCount; i++)                 list.Add(new Dummy(rand.Next(MaxVal)));          }         static void For()         {             List<Dummy> resList = new List<Dummy>();             int count = list.Count;             for (int i = 0; i < count; i++)             {                 if (list[i].Val < FilterVal)                     resList.Add(list[i]);             }                   Check(resList);         }         static void Foreach()         {             List<Dummy> resList = new List<Dummy>();             int count = list.Count;             foreach (Dummy dummy in list)             {                 if (dummy.Val < FilterVal)                     resList.Add(dummy);             }             Check(resList);         }         static void WhereToList()         {             List<Dummy> resList = list.Where(x => x.Val < FilterVal).ToList<Dummy>();             Check(resList);         }         static void WhereIEnumerable()         {             Stopwatch watch = new Stopwatch();             IEnumerable<Dummy> iEnumerable = list.Where(x => x.Val < FilterVal);             Check(iEnumerable);         }         static void FindAll()         {             List<Dummy> resList = list.FindAll(x => x.Val < FilterVal);             Check(resList);         }         public static void Run()         {             Generate();             long[] ticks = { 0, 0, 0, 0, 0 };             for (int i = 0; i < 10; i++)             {                 ticks[0] += TestTicks(For, "For \t\t");                 ticks[1] += TestTicks(Foreach, "Foreach \t");                 ticks[2] += TestTicks(WhereToList, "Where to list \t");                 ticks[3] += TestTicks(WhereIEnumerable, "Where Ienum \t");                 ticks[4] += TestTicks(FindAll, "FindAll \t");                 Console.Write("\r\n---------------");             }             for (int i = 0; i < 5; i++)                 Console.Write("\r\n"+ticks[i].ToString());         }          }      class Program     {         static void Main(string[] args)         {             WhereOrFindAll.Run();             Console.Read();         }     } } 

Results(ticks) - CheckSum enabled(some operations on results), mode: release without debugging(CTRL+F5):

 - 16,222,276 (for ->list)  - 17,151,121 (foreach -> list)  -  4,741,494 (where ->list)  - 27,122,285 (where ->ienum)  - 18,821,571 (findall ->list) 

CheckSum disabled (not using returned list at all):

 - 10,885,004 (for ->list)  - 11,221,888 (foreach ->list)  - 18,688,433 (where ->list)  -      1,075 (where ->ienum)  - 13,720,243 (findall ->list) 

Your results can be slightly different, to get real results you need more iterations.

like image 45
Wiory Avatar answered Sep 18 '22 12:09

Wiory