C#FindAll VS Where Speed

Des*_*ted 35 c# performance where findall

任何人都知道列表中Where和FindAll之间的任何速度差异.我知道IEnumerable的一部分在哪里,FindAll是List的一部分,我只是好奇什么更快.

jri*_*sta 55

List <T>类的FindAll方法实际构造一个新的列表对象,并向其添加结果.IEnumerable <T>的Where扩展方法将简单地迭代现有列表并生成匹配结果的枚举,而无需创建或添加任何内容(枚举器本身除外).

鉴于一小部分,两者可能表现相当.但是,给定一个更大的集合,Where应该优于FindAll,因为为包含结果而创建的新List必须动态增长以包含其他结果.随着匹配结果数量的增加,FindAll的内存使用量也将开始呈指数级增长,其中Where应该具有恒定的最小内存使用量(在其自身内部......排除您对结果所做的任何操作.)

  • 例外情况是您实际上希望之后有一个列表(可能需要调用`Count`或更改成员,或者多次迭代它).而`Where()`胜过`FindAll()`,`FindAll()`胜过`Where().ToList()`. (21认同)
  • @JonHanna:我最初认为我同意了,但实际上我并不确定.你有任何引用表明.ToList()比.FindAll()慢吗?在查询上调用.ToList()将是枚举的迭代,因此应该保持其内存效率.不仅如此,迭代器的某些内部实现甚至可以预先创建一个完全正确大小(内存分配)的列表,在这种情况下优于FindAll.我并不是特别不同意,但是有一个可靠的参考资料可以澄清FindAlls的好处. (6认同)
  • @Carlo:对不起,但实际上你错了.你对Wiory的回答的评论似乎没有注意到他DID通过"Check()"方法枚举每一种方法的事实......包括where-> ienum方法.Wiory的结果证实了我的答案...... FindAll比使用Where更快.此外,针对不同类型的底层集合的各种实现通常针对集合的特定机制进行优化,从而进一步提升性能(即,它并非都是纯粹的"通用"行为......它可以非常高效! ) (2认同)

Wio*_*ory 8

FindAll显然比Where慢,因为它需要创建一个新列表.

无论如何,我认为你真的应该考虑Jon Hanna的评论 - 你可能需要对你的结果做一些操作,在很多情况下列表比IEnumerable更有用.

我写了一个小测试,只需将其粘贴到Console App项目中.它测量时间/滴答:函数执行,结果收集操作(获得'真实'用法的执行,并确保编译器不会优化未使用的数据等 - 我是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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

结果(滴答) - 启用CheckSum(对结果执行某些操作),模式:不调试释放(CTRL + F5):

  • 16222276(for - > list)
  • 17151121(foreach - > list)
  • 4741494(其中 - >列表)
  • 27122285(其中 - > ienum)
  • 18821571(findall - > list)

CheckSum已禁用(根本不使用返回的列表):

  • 10885004(for - > list)
  • 11221888(foreach - > list)
  • 18688433(其中 - >列表)
  • 1075(其中 - > ienum)
  • 13720243(findall - > list)

您的结果可能略有不同,要获得真正的结果,您需要更多的迭代.

  • 抱歉,Carlo,但是即使在where-&gt; ienum实现中,他也将其称为“ Check()”方法。Check()迭代所有集合,因此他的结果完全有效。结果,这也使我的答案正确了……您称之为“严重错误”的答案。 (2认同)