Array.Count()比List.Count慢得多() [英] Array.Count() much slower than List.Count()

查看:210
本文介绍了Array.Count()比List.Count慢得多()的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在使用的扩展方法IEnumerable< T> 计数() ,数组比列表慢至少两次。

 功能计数()
名单< INT> 2299
INT [] 6903
 

这是在哪里的区别在于?

据我所知,两者都调用计数属性的ICollection

  

如果源的类型实现ICollection的,即执行用于获得元素的计数。否则,该方法确定计

对于列表返回 名单,其中,T> .Count之间 和数组, Array.Length 。此外, Array.Length 应该是快于名单,其中,T>。.Count之间

基准:

 类节目
{
    公共常量长迭代=(长)1E8;

    静态无效的主要()
    {
        VAR名单=新的名单,其中,INT>(){1};
        变种数组=新INT [1];
        数组[0] = 1;

        VAR的结果=新字典<字符串,时间跨度>();
        results.Add(名单,其中,INT>中,基准(列表,迭代));
        results.Add(INT [],基准(阵列,迭代));

        Console.WriteLine(功能.PadRight(30)+计数());
        的foreach(VAR导致的结果)
        {
            Console.WriteLine({0} {1},result.Key.PadRight(30),Math.Round(result.Value.TotalSeconds,3));
        }
        到Console.ReadLine();
    }

    公共静态时间跨度基准(IEnumerable的< INT>源,长迭代)
    {
        VAR countWatch =新的秒表();
        countWatch.Start();
        为(长I = 0; I<迭代;我++)source.Count();
        countWatch.Stop();

        返回countWatch.Elapsed;
    }
}
 


编辑:

leppie Knaģis 答案是pretty的惊人的,但我想补充的一句话。
<一href="http://msmvps.com/blogs/jon_skeet/archive/2010/12/26/reimplementing-linq-to-objects-part-7-count-and-longcount.aspx">As乔恩斯基特说:

  

有有效的两个相等的块,只是测试的   不同的集合接口类型,并且可以使用任意一个找到   第一(如果有的话)。我不知道是否为.NET实现测试   ICollection的或ICollection的&LT; T>首 - 我可以通过实施测试   当然,这两个接口,但返回的每个不同的数,   但是这可能矫枉过正。这其实并不重要了   乖巧的藏品比轻微的性能差异等    - 我们要先行先试最可能的界面,我相信这是通用的一个

通用之一可以是最有可能发生的,但如果你颠倒了两下,即打电话之前通用的一种非一般的演员阵容,Array.Count()比List.Count快一点()。而另一方面,非通用版本更慢,清单。

好知道,如果有人想叫计数()在1E8迭代循环!

 功能的ICollection&LT; T&GT;铸造ICollection的演员
表1268 1738
阵列5,925 1683
 

解决方案

原因是, Enumerable.Count&LT; T&GT;()执行强制转换为的ICollection&LT; T&GT; 检索列表和阵列的数量既

使用此示例code:

 公共静态诠释计数&LT; TSource&GT;(IEnumerable的&LT; TSource&GT;源)
{
    ICollection的&LT; TSource&GT;集合=源作为的ICollection&LT; TSource取代;
    如果(集合!= NULL)
    {
        返回1; // collection.Count;
    }
}
 

您可以判断,中投需要更长的时间为阵,其实大多采取计数的时间是从这个转换:

 功能计数()
名单&LT; INT&GT; 1575
INT [] 5069
 

键可能这个说法从文档(重点我的):

  

在.NET Framework 2.0版,Array类实现了System.Collections.Generic.IList,   了System.Collections.Generic.ICollection,和   System.Collections.Generic.IEnumerable通用接口。 的   实现提供给数组在运行时,因此是   不可见的文档生成工具。其结果是,通用   接口不会出现在对数组的声明语法   一流的,并且没有参考主题界面成员   都只能由投阵列的通用接口类型   (显式接口实现)。

When using the extension method of IEnumerable<T> Count(), an array is at least two times slower than a list.

Function                      Count()
List<int>                     2,299
int[]                         6,903

From where did the difference comes?

I understand that both are calling the Count property of ICollection:

If the type of source implements ICollection, that implementation is used to obtain the count of elements. Otherwise, this method determines the count.

For the list it returns List<T>.Count, and for array, Array.Length. Moreover, Array.Length is supposed to be faster than List<T>.Count.

Benchmark:

class Program
{
    public const long Iterations = (long)1e8;

    static void Main()
    {
        var list = new List<int>(){1};
        var array = new int[1];
        array[0] = 1;

        var results = new Dictionary<string, TimeSpan>();
        results.Add("List<int>", Benchmark(list, Iterations));
        results.Add("int[]", Benchmark(array, Iterations));

        Console.WriteLine("Function".PadRight(30) + "Count()");
        foreach (var result in results)
        {
            Console.WriteLine("{0}{1}", result.Key.PadRight(30), Math.Round(result.Value.TotalSeconds, 3));
        }
        Console.ReadLine();
    }

    public static TimeSpan Benchmark(IEnumerable<int> source, long iterations)
    {
        var countWatch = new Stopwatch();
        countWatch.Start();
        for (long i = 0; i < iterations; i++) source.Count();
        countWatch.Stop();

        return countWatch.Elapsed;
    }
}


Edit:

leppie and Knaģis answers are pretty amazing, but I want to add a remark.
As Jon Skeet said:

There are effectively two equivalent blocks, just testing for different collection interface types, and using whichever one it finds first (if any). I don't know whether the .NET implementation tests for ICollection or ICollection< T > first - I could test it by implementing both interfaces but returning different counts from each, of course, but that's probably overkill. It doesn't really matter for well-behaved collections other than the slight performance difference - we want to test the "most likely" interface first, which I believe is the generic one.

The generic one could be the most likely to happens, but if you invert the two, ie call the non generic cast before the generic one, Array.Count() becomes a little faster than List.Count(). On the other hand, non generic version is slower for List.

Good to know if anyone want to call Count() in an 1e8 iterations loop!

Function       ICollection<T> Cast     ICollection Cast
List                1,268                   1,738         
Array               5,925                   1,683

解决方案

The reason is that Enumerable.Count<T>() performs a cast to ICollection<T> to retrieve the count both from the list and the array.

Using this sample code:

public static int Count<TSource>(IEnumerable<TSource> source)
{
    ICollection<TSource> collection = source as ICollection<TSource>;
    if (collection != null)
    {
        return 1; // collection.Count;
    }
}

you can determine that the cast takes much longer for the array, in fact most of the time taken for counting is from this cast:

Function                      Count()
List<int>                     1,575
int[]                         5,069

The key might be this statement from the documentation (emphasis mine):

In the .NET Framework version 2.0, the Array class implements the System.Collections.Generic.IList, System.Collections.Generic.ICollection, and System.Collections.Generic.IEnumerable generic interfaces. The implementations are provided to arrays at run time, and therefore are not visible to the documentation build tools. As a result, the generic interfaces do not appear in the declaration syntax for the Array class, and there are no reference topics for interface members that are accessible only by casting an array to the generic interface type (explicit interface implementations).

这篇关于Array.Count()比List.Count慢得多()的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆