在LINQ查询中,是调用ToList()还是ToArray()更好?

31 浏览
0 Comments

在LINQ查询中,是调用ToList()还是ToArray()更好?

我经常遇到这样的情况:我想在声明查询时立即评估它。这通常是因为我需要多次迭代它而且计算代价昂贵。例如:

string raw = "...";
var lines = (from l in raw.Split('\n')
             let ll = l.Trim()
             where !string.IsNullOrEmpty(ll)
             select ll).ToList();

这很好用。但如果我不打算修改结果,那我可能可以直接调用 ToArray() 而不是 ToList()

我想知道 ToArray() 是否是通过首先调用 ToList() 实现的,因此比直接调用 ToList() 的内存效率更低。

我疯了吗?我应该只调用 ToArray()吗,放心,知道内存不会分配两次吗?

admin 更改状态以发布 2023年5月20日
0
0 Comments

性能的差别将是微不足道的,因为List是作为一个动态大小的数组实现的。调用ToArray()(它使用一个内部Buffer类来增长数组)或ToList()(它调用List(IEnumerable)构造函数)最终都是把它们放入数组中并不断增长数组直到所有元素都放入。

如果你想得到这个事实的确切证实,请查看Reflector中这些方法的实现,你会看到它们归结为几乎相同的代码。

0
0 Comments

除非你只是需要一个数组来满足其他约束条件,否则你应该使用ToList。在大多数情况下,ToArrayToList分配更多的内存。

两者都使用数组进行存储,但ToList具有更灵活的限制。它需要数组至少与集合中的元素数量一样大。如果数组更大,那没问题。然而,ToArray需要数组的大小正好等于元素的数量。

为了满足这个限制,ToArray通常比ToList多分配一个数组。一旦它有一个足够大的数组,它就会分配一个大小完全正确的数组,并将元素复制回该数组。它能够避免这种情况的唯一时间是当数组的增长算法恰好与需要存储的元素数量重合时(绝对是少数情况)。

编辑

有几个人问我在List值中有额外未使用的内存的后果。

这是一个有效的担忧。如果创建的集合具有长生命周期,在创建后从未被修改,并且在Gen2堆中具有很高的概率,则最好在一开始就将ToArray的额外分配作为开销。

总的来说,我认为这是较少见的情况。更常见的是看到许多ToArray调用,它们立即传递给其他短期内存使用,在这种情况下,ToList显然更好。

关键在于进行性能分析,性能分析以及更多性能分析。

0