我在 c# 中工作,我正在创建一个列表(newList),我可以从另一个列表(otherList)的长度中获取它。在 c# 中,列表的实现方式是使用 otherList.Count 或只使用 newList.Add(obj) 而不担心长度来预先分配列表的长度以提高性能?
4 回答
实现以下构造函数List<T>
的目的是为了提高像您这样的场景中的性能:
http://msdn.microsoft.com/en-us/library/dw8e0z9z.aspx
public List(int capacity)
只需在构造函数中传递容量。
newList = new List<string>(otherList.Count);
如果您知道新列表的确切长度,那么使用该容量创建它确实会执行 - 有点 - 更好。
原因是List<T>
内部的实现使用了数组。如果它变得太小,则会创建一个新数组,并将旧数组中的项目复制到新项目中。
a的容量是 可以容纳
List<T>
的元素的数量。List<T>
当元素添加到 aList<T>
时,容量会根据需要通过重新分配内部数组自动增加。如果可以估计集合的大小,那么指定初始容量就无需在向
List<T>
.可以通过调用 TrimExcess 方法或显式设置容量属性来减少容量。减少容量会重新分配内存并复制
List<T>
.
因此,如果您估计要填充的列表的大小,这将表明性能会有所提高。当然,另一方面是分配的列表太大,因此不必要地占用了内存。
老实说,除非我真的需要,否则我不会担心这种微优化。
所以我对预分配的场景进行了基准测试,只是想分享一些数字。代码只是把这个时间:
var repetitions = 100000000
var list = new List<object>();
for (var i = 0; i < repetitions; i++)
list.Add(new object());
比较是通过在列表中分配确切的重复次数,两倍的数量并且没有预分配。这是时代:
- 未预先分配的列表:6561、6394、6556、6283、6466
- 预分配列表:5951、6037、5885、6044、5996
- 列出双重预分配:6710、6665、6729、6760、6624
那么预分配值得吗?是的,如果列表中的对象数量已知,或者该数量的底线已知(列表中至少有多少项目)。
如果不是这样,您实际上可能会浪费更多的时间和内存,因为预分配将使用时间和内存来为所需的分配腾出空间。
请注意,同样在内存方面,精确的预分配是最节省内存的,因为不进行预分配会使您的列表增长超过所需的最紧容量。