c# performance where findall

C#FindAll VS donde velocidad



performance where (5)

El método FindAll de la clase List <T> realmente construye un nuevo objeto de lista y le agrega resultados. El método de extensión Where para IEnumerable <T> 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).

Dado un pequeño conjunto, los dos probablemente se desempeñarían de forma comparable. Sin embargo, dado un conjunto más grande, Where debería superar a FindAll, ya que la nueva lista creada para contener los resultados tendrá que crecer dinámicamente para contener resultados adicionales. El uso de la memoria de FindAll también comenzará a crecer exponencialmente a medida que aumente el número de resultados coincidentes, mientras que Where debería tener un uso de memoria mínimo constante (en sí mismo ... excluyendo lo que haga con los resultados).

Alguien sabe las diferencias de velocidad entre Dónde y Buscar todo en la lista. Sé dónde es parte de IEnumerable y FindAll es parte de List, solo tengo curiosidad por saber qué es más rápido.


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

De todos modos, creo que realmente deberías considerar el comentario de Jon Hanna, probablemente necesites hacer algunas operaciones con tus resultados y la lista sería más útil que IEnumerable en muchos casos.

Escribí una pequeña prueba, solo péguelo en el proyecto de la aplicación de consola. Mide el tiempo / tics de: ejecución de la función, operaciones en la recolección de resultados (para obtener el rendimiento del uso "real", y para asegurarse de que el compilador no optimice los datos no utilizados, etc. - Soy nuevo en C # y no lo hago saber cómo funciona todavía, lo siento).

Aviso: cada función medida excepto WhereIENumerable () crea una nueva Lista de elementos. Podría estar haciendo algo mal, pero iterar claramente IEnumerable lleva mucho más tiempo que iterar en la lista.

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

Resultados (tics) - CheckSum habilitado (algunas operaciones en los resultados), modo: lanzamiento sin depuración (CTRL + F5):

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

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

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

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


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


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

Sin embargo, tenga en cuenta que .Where () es enumerable, no crea activamente una lista en la memoria y la llena. Es más como una secuencia, por lo que el uso de memoria en algo muy grande puede tener una diferencia significativa. Además, podría comenzar a usar los resultados de forma paralela mucho más rápido usando allí. Enfoque WHERE () en 4.0.


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 acaba de crear una consulta. En realidad, no hace nada, a diferencia de FindAll que crea una lista.