C# FindAll VS где скорость

кто-нибудь знает какие-либо различия в скорости между Where и FindAll в списке. Я знаю, где часть IEnumerable и FindAll является частью списка, мне просто интересно, что быстрее.

5 ответов


метод FindAll класса List фактически создает новый объект list и добавляет к нему результаты. Метод расширения Where для IEnumerable будет просто перебирать существующий список и давать перечисление результатов сопоставления без создания или добавления чего-либо (кроме самого перечислителя.)

учитывая небольшой набор, эти два, вероятно, будут работать сопоставимо. Однако, учитывая больший набор, где должен превзойти FindAll, так как новый список, созданный для содержания результаты должны будут динамически расти, чтобы содержать дополнительные результаты. Использование памяти FindAll также начнет расти экспоненциально по мере увеличения числа результатов сопоставления, где, как и где должно быть постоянное минимальное использование памяти (само по себе...кроме все что вы делаете с результатами.)


FindAll явно медленнее, чем Where, потому что ему нужно создать новый список.

в любом случае, я думаю, вы действительно должны рассмотреть комментарий Джона Ханны - вам, вероятно, нужно будет сделать некоторые операции над вашими результатами, и список будет более полезным, чем IEnumerable во многих случаях.

Я написал небольшой тест, просто вставьте его в проект консольного приложения. Он измеряет время / тики: выполнение функции, операции по сбору результатов(для получения perf. "реального" использования, и быть уверенным, что компилятор не оптимизирует неиспользуемые данные и т. д. - Я новичок в C# и еще не знаю,как это работает, извините).

Примечание: каждая измеренная функция, кроме WhereIENumerable (), создает новый список элементов. Возможно, я делаю что-то неправильно, но очевидно, что итерация IEnumerable занимает гораздо больше времени, чем итерация списка.

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();
        }
    }
}

результаты(ТИКов) - контрольная сумма включена (некоторые операции с результатами), режим: выпуск без отладки (CTRL+F5):

  • 16222276 (для ->список)
  • 17151121 (foreach -> список)
  • 4741494 (где ->список)
  • 27122285 (где - >ienum)
  • 18821571 (findall ->список)

контрольная сумма отключена (не используя возвращенный список вообще):

  • 10885004 (для ->список)
  • 11221888 (foreach ->список)
  • 18688433 (где ->список)
  • 1075 (где ->ienum)
  • 13720243 (метод findAll ->список)

ваши результаты могут немного отличаться, чтобы получить реальные результаты, вам нужно больше итераций.


.FindAll() должно быть быстрее, он использует уже зная размер списка и цикл через внутренний массив с помощью простого for петли. .Where() должен запустить перечислитель (запечатанный класс framework с именем WhereIterator в этом случае) и выполнять ту же работу менее определенным образом.

имейте в виду, что .Где () является перечисляемым, а не активно создает список в памяти и заполняет его. Это больше похоже на поток, поэтому использование памяти на чем-то очень большом может иметь существенное различие. Кроме того, вы можете начать использовать результаты параллельно гораздо быстрее, используя там .Где() подход в 4.0.


Where намного, намного быстрее, чем FindAll. Независимо от того, насколько велик список,Where занимает ровно столько же времени.

конечно Where просто создает запрос. Он ничего не делает, в отличие от FindAll, который создает список.


ответ от jrista имеет смысл. Однако новый список добавляет те же объекты, таким образом, просто растет по отношению к существующим объектам, которые не должны быть такими медленными. Пока возможно расширение 3.5 / Linq, где все равно лучше. FindAll имеет гораздо больше смысла, когда ограничен 2.0