使用 IEnumerable<T>
的扩展方法 Count()
时,数组的速度至少比列表慢两倍。
Function Count()
List<int> 2,299
int[] 6,903
这个差异从哪里来?
我理解两者都在调用ICollection
的Count
属性:
如果源类型实现了ICollection,则使用该实现获取元素的计数。否则,此方法确定计数。
对于列表,它返回List<T>.Count
,而对于数组,则返回Array.Length
。此外,Array.Length
应该比List<T>.Count
更快。
基准测试:
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;
}
}
编辑:
leppie 和 Knaģis 的回答相当出色,但我想补充一点。
正如Jon Skeet所说:
实际上有两个等效的块,只是测试不同的集合接口类型,并使用它找到的任何一个(如果有)。 我不知道.NET实现是否优先测试ICollection或ICollection<T> - 当然我可以通过实现两个接口并从中返回不同的计数来测试它,但那可能过度杀伤了。 对于表现良好的集合而言,这不是真正重要的,除了微小的性能差异之外 - 我们希望首先测试“最有可能”的接口,我认为是通用的接口。
通用接口可能是最有可能发生的,但如果你颠倒它们,也就是在调用通用接口之前先调用非通用转换,Array.Count() 比 List.Count() 稍微快一点。另一方面,对于List,非通用版本较慢。
如果有人想在1e8个迭代循环中调用Count()
,那么这是好的知识!
Function ICollection<T> Cast ICollection Cast
List 1,268 1,738
Array 5,925 1,683
O_o
- leppie