包含,存在和任何的性能基准测试

har*_*hit 60 c# performance benchmarking

我一直在寻找之间的性能基准测试Contains,Exists以及Any方法可用List<T>.我只想出于好奇而发现这一点,因为我总是在这些中感到困惑.关于SO的许多问题描述了这些方法的定义,例如:

  1. LINQ Ring:任何()vs Contains()用于巨大的集合
  2. Linq.任何VS.Exists - 有什么区别?
  3. LINQ扩展方法 - Any()vs. Where()vs. Exists()

所以我决定自己做.我将其添加为答案.对结果有任何更多见解是最受欢迎的.我还对数组进行了基准测试以查看结果

har*_*hit 70

根据文件:

List.Exists(对象方法)

确定List(T)是否包含与指定谓词定义的条件匹配的元素.

IEnumerable.Any(扩展方法)

确定序列的任何元素是否满足条件.

List.Contains(对象方法)

确定元素是否在List中.

标杆:

码:

    static void Main(string[] args)
    {
        ContainsExistsAnyShort();

        ContainsExistsAny();
    }

    private static void ContainsExistsAny()
    {
        Console.WriteLine("***************************************");
        Console.WriteLine("********* ContainsExistsAny ***********");
        Console.WriteLine("***************************************");

        List<int> list = new List<int>(6000000);
        Random random = new Random();
        for (int i = 0; i < 6000000; i++)
        {
            list.Add(random.Next(6000000));
        }
        int[] arr = list.ToArray();

        find(list, arr);
    }

    private static void ContainsExistsAnyShort()
    {
        Console.WriteLine("***************************************");
        Console.WriteLine("***** ContainsExistsAnyShortRange *****");
        Console.WriteLine("***************************************");

        List<int> list = new List<int>(2000);
        Random random = new Random();
        for (int i = 0; i < 2000; i++)
        {
            list.Add(random.Next(6000000));
        }
        int[] arr = list.ToArray();

        find(list, arr);
    }

    private static void find(List<int> list, int[] arr)
    {
        Random random = new Random();
        int[] find = new int[10000];
        for (int i = 0; i < 10000; i++)
        {
            find[i] = random.Next(6000000);
        }

        Stopwatch watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 10000; rpt++)
        {
            list.Contains(find[rpt]);
        }
        watch.Stop();
        Console.WriteLine("List/Contains: {0:N0}ms", watch.ElapsedMilliseconds);

        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 10000; rpt++)
        {
            list.Exists(a => a == find[rpt]);
        }
        watch.Stop();
        Console.WriteLine("List/Exists: {0:N0}ms", watch.ElapsedMilliseconds);

        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 10000; rpt++)
        {
            list.Any(a => a == find[rpt]);
        }
        watch.Stop();
        Console.WriteLine("List/Any: {0:N0}ms", watch.ElapsedMilliseconds);

        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 10000; rpt++)
        {
            arr.Contains(find[rpt]);
        }
        watch.Stop();
        Console.WriteLine("Array/Contains: {0:N0}ms", watch.ElapsedMilliseconds);

        Console.WriteLine("Arrays do not have Exists");

        watch = Stopwatch.StartNew();
        for (int rpt = 0; rpt < 10000; rpt++)
        {
            arr.Any(a => a == find[rpt]);
        }
        watch.Stop();
        Console.WriteLine("Array/Any: {0:N0}ms", watch.ElapsedMilliseconds);
    }
Run Code Online (Sandbox Code Playgroud)

结果

***************************************
***** ContainsExistsAnyShortRange *****
***************************************
List/Contains: 96ms
List/Exists: 146ms
List/Any: 381ms
Array/Contains: 34ms
Arrays do not have Exists
Array/Any: 410ms
***************************************
********* ContainsExistsAny ***********
***************************************
List/Contains: 257,996ms
List/Exists: 379,951ms
List/Any: 884,853ms
Array/Contains: 72,486ms
Arrays do not have Exists
Array/Any: 1,013,303ms
Run Code Online (Sandbox Code Playgroud)

  • “数组不存在”?`Array.Exists(` https://learn.microsoft.com/en-us/dotnet/api/system.array.exists?view=netframework-4.7.2 (4认同)
  • 你是什​​么意思:“数组不存在”?我认为它有 Exists():/sf/answers/1605012391/ (2认同)

wer*_*zui 53

最快的方法是使用HashSet.的Contains一个HashSet是O(1).

我带了你的代码并添加了一个基准,HashSet<int> 性能成本HashSet<int> set = new HashSet<int>(list);几乎为零.

void Main()
{
    ContainsExistsAnyShort();

    ContainsExistsAny();
}

private static void ContainsExistsAny()
{
    Console.WriteLine("***************************************");
    Console.WriteLine("********* ContainsExistsAny ***********");
    Console.WriteLine("***************************************");

    List<int> list = new List<int>(6000000);
    Random random = new Random();
    for (int i = 0; i < 6000000; i++)
    {
        list.Add(random.Next(6000000));
    }
    int[] arr = list.ToArray();
    HashSet<int> set = new HashSet<int>(list);

    find(list, arr, set);

}

private static void ContainsExistsAnyShort()
{
    Console.WriteLine("***************************************");
    Console.WriteLine("***** ContainsExistsAnyShortRange *****");
    Console.WriteLine("***************************************");

    List<int> list = new List<int>(2000);
    Random random = new Random();
    for (int i = 0; i < 2000; i++)
    {
        list.Add(random.Next(6000000));
    }
    int[] arr = list.ToArray();
    HashSet<int> set = new HashSet<int>(list);

    find(list, arr, set);

}

private static void find(List<int> list, int[] arr, HashSet<int> set)
{
    Random random = new Random();
    int[] find = new int[10000];
    for (int i = 0; i < 10000; i++)
    {
        find[i] = random.Next(6000000);
    }

    Stopwatch watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        list.Contains(find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("List/Contains: {0}ms", watch.ElapsedMilliseconds);

    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        list.Exists(a => a == find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("List/Exists: {0}ms", watch.ElapsedMilliseconds);

    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        list.Any(a => a == find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("List/Any: {0}ms", watch.ElapsedMilliseconds);

    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        arr.Contains(find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("Array/Contains: {0}ms", watch.ElapsedMilliseconds);

    Console.WriteLine("Arrays do not have Exists");

    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        arr.Any(a => a == find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("Array/Any: {0}ms", watch.ElapsedMilliseconds);

    watch = Stopwatch.StartNew();
    for (int rpt = 0; rpt < 10000; rpt++)
    {
        set.Contains(find[rpt]);
    }
    watch.Stop();
    Console.WriteLine("HashSet/Contains: {0}ms", watch.ElapsedMilliseconds);
}
Run Code Online (Sandbox Code Playgroud)

结果

***************************************
***** ContainsExistsAnyShortRange *****
***************************************
List/Contains: 65ms
List/Exists: 106ms
List/Any: 222ms
Array/Contains: 20ms
Arrays do not have Exists
Array/Any: 281ms
HashSet/Contains: 0ms
***************************************
********* ContainsExistsAny ***********
***************************************
List/Contains: 120522ms
List/Exists: 250445ms
List/Any: 653530ms
Array/Contains: 40801ms
Arrays do not have Exists
Array/Any: 522371ms
HashSet/Contains: 3ms
Run Code Online (Sandbox Code Playgroud)


Luc*_*ain 5

值得一提的是,这种比较有点不公平,因为Array类不拥有该Contains()方法。IEnumerable<T>它使用via 顺序 的扩展方法Enumerator,因此它没有针对Array实例进行优化。另一方面,HashSet<T>它有自己的实现,针对所有尺寸进行了全面优化。

int Array.IndexOf()为了公平比较,您可以使用为实例实现的静态方法Array,尽管它使用的for循环比Enumerator.

使用公平比较算法,最多 5 个元素的小型集合的性能HashSet<T>.Contains()与 类似Array.IndexOf(),但对于较大的集合效率更高。