C# FindAll VS Where Speed

后端 未结 5 886
不思量自难忘°
不思量自难忘° 2020-12-05 22:49

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.

5条回答
  •  隐瞒了意图╮
    2020-12-05 23:15

    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 list = new List();
            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 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 ieNumerable)
            {
                if (!CheckSum) return;
                Stopwatch watch = new Stopwatch();
                watch.Start();
    
                IEnumerator 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 resList = new List();
                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 resList = new List();
                int count = list.Count;
                foreach (Dummy dummy in list)
                {
                    if (dummy.Val < FilterVal)
                        resList.Add(dummy);
                }
                Check(resList);
            }
            static void WhereToList()
            {
                List resList = list.Where(x => x.Val < FilterVal).ToList();
                Check(resList);
            }
            static void WhereIEnumerable()
            {
                Stopwatch watch = new Stopwatch();
                IEnumerable iEnumerable = list.Where(x => x.Val < FilterVal);
                Check(iEnumerable);
            }
            static void FindAll()
            {
                List 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.

提交回复
热议问题