C # findAll VS Where Velocidad


Cualquiera conoce las diferencias de velocidad entre Where y findAll en la lista. Sé dónde es parte deumumerable y findAll es parte de List, solo tengo curiosidad por saber qué es más rápido.

Author: Dested, 2010-02-14

5 answers

El método findAll de la clase List en realidad construye un nuevo objeto list y le agrega resultados. El método de extensión Where paraEnumerable simplemente iterará sobre una lista existente y producirá una enumeración de los resultados coincidentes sin crear o agregar nada (que no sea el enumerador en sí.)

Dado un conjunto pequeño, los dos probablemente se desempeñarían de manera comparable. Sin embargo, dado un conjunto más grande, Donde debe superar a findAll, como la nueva Lista creada para contener los resultados tendrá que crecer dinámicamente para contener resultados adicionales. El uso de memoria de findAll también comenzará a crecer exponencialmente a medida que aumenta el número de resultados coincidentes, donde como Donde debería tener un uso de memoria mínimo constante (en y por sí mismo...excluyendo lo que hagas con los resultados.)

 47
Author: jrista,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-14 05:31:31

FindAll es obviamente más lento que Where, porque necesita crear una nueva lista.

De todos modos, creo que realmente debería considerar el comentario de Jon Hanna: probablemente necesitará hacer algunas operaciones en sus resultados y la lista sería más útil queumumerable en muchos casos.

Escribí una pequeña prueba, solo pégala en el proyecto de la aplicación de consola. Mide el tiempo / ticks de: ejecución de funciones, operaciones en la colección de resultados (para obtener perf. de uso 'real' , y para estar seguro de que el compilador no optimizar los datos no utilizados, etc. - Soy nuevo en C# y no sé cómo funciona todavía,lo siento).

Aviso: cada función medida excepto WhereIENumerable() crea una nueva Lista de elementos. Puede que esté haciendo algo mal, pero claramente iterarerableumerable toma mucho más tiempo que iterar 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 habilitado(algunas operaciones en los resultados), modo: release without debugging(CTRL+F5):

  • 16222276 (para ->lista)
  • 17151121 (foreach - >list)
  • 4741494 (donde ->lista)
  • 27122285 (donde->enum)
  • 18821571 (findall ->list)

CheckSum deshabilitado (no se usa la lista devuelta en absoluto):

  • 10885004 (para ->lista)
  • 11221888 (foreach ->list)
  • 18688433 (donde ->lista)
  • 1075 (donde->enum)
  • 13720243 (findall ->list)

Sus resultados pueden ser ligeramente diferentes, para obtener resultados reales necesita más iteraciones.

 6
Author: Wiory,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-23 11:41:39

.FindAll() debería ser más rápido, se aprovecha de conocer ya el tamaño de la Lista y loopear a través de la matriz interna con un simple bucle for. .Where() tiene que encender un enumerador (una clase de framework sellado llamada WhereIterator en este caso) y hacer el mismo trabajo de una manera menos específica.

Tenga en cuenta, sin embargo, que .Donde () es enumerable, no creando activamente una Lista en memoria y llenándola. Es más como un flujo, por lo que el uso de memoria en algo muy grande puede tener un significativo diferencia. También, usted podría comenzar a utilizar los resultados de una manera paralela mucho más rápido usando allí .Donde () aproximación en 4.0.

 3
Author: Nick Craver,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-02-14 05:32:33

Where es mucho, mucho más rápido que FindAll. No importa cuán grande sea la lista, Where toma exactamente la misma cantidad de tiempo.

Por supuesto, Where simplemente crea una consulta. En realidad no hace nada, a diferencia de FindAll que crea una lista.

 3
Author: Jonathan Allen,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-04-02 13:12:53

La respuesta de jrista hace sentido. Sin embargo, la nueva lista agrega los mismos objetos, por lo que solo crece con referencia a los objetos existentes, que no deberían ser tan lentos. Siempre y cuando la extensión 3.5 / Linq sea posible, Donde se mantiene mejor de todos modos. findAll tiene mucho más sentido cuando está limitado con 2.0

 -3
Author: Eric,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-07-15 12:31:41