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(); } } }Results (ticks) - включена контрольная сумма (некоторые операции с результатами), режим: релиз без отладки (CTRL+F5):
- 16222276 (для - > список)
- 17151121 (foreach - >список)
- 4741494 (где ->список)
- 27122285 (где ->ienum)
- 18821571 (findall - > list)
Контрольная сумма отключена (не используется возвращаемый список вообще):
- 10885004 (для - > список)
- 11221888 (foreach - > list)
- 18688433 (где ->список)
- 1075 (где ->ienum)
- 13720243 (findall - > list)
Ваши результаты могут немного отличаться, чтобы получить реальные результаты, вам нужно больше итераций.
.FindAll()должно быть быстрее, он использует преимущество уже зная размер списка и петля через внутренний массив с помощью простого циклаfor..Where()должен запустить перечислитель (в данном случае закрытый класс фреймворка, называемыйWhereIterator) и выполнить ту же работу менее специфическим способом.Имейте, однако, в виду, что .Where () является перечислимым, не создавая активно список в памяти и не заполняя его. Это больше похоже на поток, поэтому использование памяти на чем-то очень большом может иметь значительное значение. разница. Кроме того, вы можете начать использовать результаты в параллельном режиме гораздо быстрее, используя там .Где () подход в 4.0.
Whereгораздо, гораздо быстрее, чемFindAll. Независимо от того, насколько велик список,Whereзанимает ровно столько же времени.Конечно,
Whereпросто создает запрос. На самом деле он ничего не делает, в отличие отFindAll, который создает список.
Ответ от джристы имеет смысл. Однако новый список добавляет те же объекты, таким образом, просто растет по отношению к существующим объектам, которые не должны быть такими медленными. Пока расширение 3.5 / Linq возможно, где остается лучше в любом случае. FindAll имеет гораздо больше смысла, когда ограничен 2.0
Comments