Linq .Any VS.Exists - 有什么区别?

在集合上使用Linq,如下代码行之间有什么区别? dom

if(!coll.Any(i => i.Value))

ide

if(!coll.Exists(i => i.Value))

更新1 性能

当我反汇编.Exists看起来没有代码。 测试

更新2 spa

任何人都知道为何这个没有代码? pwa


#1楼

TLDR; 性能方面Any看起来都比较慢 (若是我已正确设置它以几乎同时评估这两个值) code

var list1 = Generate(1000000);
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s +=" Any: " +end1.Subtract(start1);
            }

            if (!s.Contains("sdfsd"))
            {

            }

测试列表生成器: orm

private List<string> Generate(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            list.Add( new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    new RNGCryptoServiceProvider().GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray())); 
        }

        return list;
    }

拥有10M记录 ip

“任何:00:00:00.3770377存在:00:00:00.2490249” get

有5M记录

“任何:00:00:00.0940094存在:00:00:00.1420142”

拥有1M记录

“任何:00:00:00.0180018存在:00:00:00.0090009”

使用500k,(我也按顺序翻转它们进行评估,以查看是否没有与先运行的任何操做相关联的额外操做。)

“存在:00:00:00.0050005任何:00:00:00.0100010”

拥有100k记录

“存在:00:00:00.0010001任何:00:00:00.0020002”

彷佛Any比较慢的2级。

编辑:对于5和10M记录,我改变了它生成列表的方式,而且Exists忽然变得慢于Any ,这意味着我测试的方式有问题。

新的测试机制:

private static IEnumerable<string> Generate(int count)
    {
        var cripto = new RNGCryptoServiceProvider();
        Func<string> getString = () => new string(
            Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ", 13)
                .Select(s =>
                {
                    var cryptoResult = new byte[4];
                    cripto.GetBytes(cryptoResult);
                    return s[new Random(BitConverter.ToInt32(cryptoResult, 0)).Next(s.Length)];
                })
                .ToArray());

        var list = new ConcurrentBag<string>();
        var x = Parallel.For(0, count, o => list.Add(getString()));
        return list;
    }

    private static void Test()
    {
        var list = Generate(10000000);
        var list1 = list.ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;

            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {

            }
        }

Edit2:好的,为了消除生成测试数据的任何影响我把它所有写到文件中,如今从那里读取它。

private static void Test()
    {
        var list1 = File.ReadAllLines("test.txt").Take(500000).ToList();
        var forceListEval = list1.SingleOrDefault(o => o == "0123456789012");
        if (forceListEval != "sdsdf")
        {
            var s = string.Empty;
            var start1 = DateTime.Now;
            if (!list1.Any(o => o == "0123456789012"))
            {
                var end1 = DateTime.Now;
                s += " Any: " + end1.Subtract(start1);
            }

            var start2 = DateTime.Now;
            if (!list1.Exists(o => o == "0123456789012"))
            {
                var end2 = DateTime.Now;
                s += " Exists: " + end2.Subtract(start2);
            }

            if (!s.Contains("sdfsd"))
            {
            }
        }
    }

10M

“任何:00:00:00.1640164存在:00:00:00.0750075”

5M

“任何:00:00:00.0810081存在:00:00:00.0360036”

1M

“任何:00:00:00.0190019存在:00:00:00.0070007”

500K

“任何:00:00:00.0120012存在:00:00:00.0040004”

在此输入图像描述


#2楼

做为Matas关于基准测试的答案的延续。

TL / DR :Exists()和Any()一样快。

首先:使用秒表进行基准测试并不精确( 请参阅series0ne关于不一样但相似的主题的答案 ),但它比DateTime精确得多。

得到真正精确读数的方法是使用性能分析。 可是,了解两种方法的性能如何相互衡量的一种方法是经过执行两种方法加载次数,而后比较每种方法的最快执行时间。 这样,JITing和其余噪音给咱们带来了糟糕的读数(而且确实如此并不重要 ,由于两种执行在某种意义上都是“ 一样错误的 ”。

static void Main(string[] args)
    {
        Console.WriteLine("Generating list...");
        List<string> list = GenerateTestList(1000000);
        var s = string.Empty;

        Stopwatch sw;
        Stopwatch sw2;
        List<long> existsTimes = new List<long>();
        List<long> anyTimes = new List<long>();

        Console.WriteLine("Executing...");
        for (int j = 0; j < 1000; j++)
        {
            sw = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw.Stop();
                existsTimes.Add(sw.ElapsedTicks);
            }
        }

        for (int j = 0; j < 1000; j++)
        {
            sw2 = Stopwatch.StartNew();
            if (!list.Exists(o => o == "0123456789012"))
            {
                sw2.Stop();
                anyTimes.Add(sw2.ElapsedTicks);
            }
        }

        long existsFastest = existsTimes.Min();
        long anyFastest = anyTimes.Min();

        Console.WriteLine(string.Format("Fastest Exists() execution: {0} ticks\nFastest Any() execution: {1} ticks", existsFastest.ToString(), anyFastest.ToString()));
        Console.WriteLine("Benchmark finished. Press any key.");
        Console.ReadKey();
    }

    public static List<string> GenerateTestList(int count)
    {
        var list = new List<string>();
        for (int i = 0; i < count; i++)
        {
            Random r = new Random();
            int it = r.Next(0, 100);
            list.Add(new string('s', it));
        }
        return list;
    }

在执行上面的代码4次以后(在1 000 000个元素的列表上执行1 000 Exists()Any() ),不难看出这些方法几乎一样快。

Fastest Exists() execution: 57881 ticks
Fastest Any() execution: 58272 ticks

Fastest Exists() execution: 58133 ticks
Fastest Any() execution: 58063 ticks

Fastest Exists() execution: 58482 ticks
Fastest Any() execution: 58982 ticks

Fastest Exists() execution: 57121 ticks
Fastest Any() execution: 57317 ticks

一个细微的差异,但它过小,不被背景噪音来解释差别。 个人猜想是,若是一我的会作10 000或10万Exists()Any() ,那么这个微小的差别会或多或少地消失。


#3楼

当您更正测量值时 - 如上所述:任意和存在,并添加平均值 - 咱们将得到如下输出:

Executing search Exists() 1000 times ... 
Average Exists(): 35566,023
Fastest Exists() execution: 32226 

Executing search Any() 1000 times ... 
Average Any(): 58852,435
Fastest Any() execution: 52269 ticks

Benchmark finished. Press any key.

#4楼

区别在于Any是System.Linq.Enumerable上定义的任何IEnumerable<T>的扩展方法。 它能够在任何IEnumerable<T>实例上使用。

存在彷佛不是一种扩展方法。 个人猜想是coll的类型为List<T> 。 若是是这样Exists是一个实例方法,其功能与Any很是类似。

简而言之这些方法基本相同。 一个比另外一个更广泛。

  • 任何也有一个不带参数的重载,只是查找枚举中的任何项目。
  • 存在没有这种过载。

#5楼

此外,这仅在Value为bool类型时才有效。 一般,这与谓词一块儿使用。 一般使用任何谓词来查找是否存在知足给定条件的任何元素。 在这里,您只须要从元素i到bool属性进行映射。 它将搜索Value属性为true的“i”。 完成后,该方法将返回true。

相关文章
相关标签/搜索