Подтвердить что ты не робот

С# FindAll VS Где скорость

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

4b9b3361

Ответ 1

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

Учитывая небольшой набор, они, вероятно, будут выполняться сравнительно. Тем не менее, учитывая больший набор, Where's outperform FindAll, поскольку новый список, созданный для того, чтобы содержать результаты, должен динамически расти, чтобы содержать дополнительные результаты. Использование памяти FindAll также начнет экспоненциально возрастать по мере увеличения количества совпадающих результатов, так как Where должно иметь постоянное минимальное использование памяти (само по себе... исключая все, что вы делаете с результатами.)

Ответ 2

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

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

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

Обратите внимание: каждая измеренная функция, кроме 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();
        }
    }
}

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

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

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

  • 10885004 (для → список)
  • 11221888 (foreach → список)
  • 18688433 (где → список)
  • 1075 (где → ienum)
  • 13720243 (findall → list)

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

Ответ 3

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

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

Ответ 4

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

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

Ответ 5

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