【发布时间】:2013-04-25 07:37:27
【问题描述】:
当使用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 的答案非常棒,但我想补充一句。
As Jon Skeet said:
实际上有两个等效的块,只是测试 不同的集合接口类型,并使用它找到的任何一个 首先(如果有)。我不知道 .NET 实现是否测试 首先是 ICollection 或 ICollection - 我可以通过实现来测试它 当然,这两个接口都返回不同的计数, 但这可能是矫枉过正。这并不重要 除了轻微的性能差异之外,表现良好的集合 - 我们想首先测试“最有可能”的接口,我认为这是通用接口。
泛型最有可能发生,但是如果你将两者颠倒过来,即在泛型之前调用非泛型转换,Array.Count() 会比 List.Count() 快一点。另一方面,非泛型版本的 List 速度较慢。
很高兴知道是否有人想在 1e8 迭代循环中调用 Count()!
Function ICollection<T> Cast ICollection Cast
List 1,268 1,738
Array 5,925 1,683
【问题讨论】:
-
+1 有趣。此外,根据您的数字,您似乎正在运行 64 位。在 32 位中,差别更大!
-
我的测试实际上慢了 四倍!最有趣的。
-
在 32 位中,对我来说慢了大约 38 倍
O_o
标签: c# .net performance linq ienumerable