我正在遍历一个潜在的巨大(数百万项)数据集(存储在磁盘上)并提取我要添加到 List<T>
中的选定项目.当我向列表中添加一个项目时,我会在它周围加一个锁,因为还有其他线程正在访问该列表。
我正在尝试在两种可能的实现之间做出决定:
1) 每次需要添加项目时锁定列表。
2) 使用临时列表,我在找到项目时将其添加到其中,然后使用 List<T>.AddRange()
将该列表中的项目添加到一个 block 中(例如,当我找到 1000 个匹配项时)。这导致需要较少地请求锁定列表,但如果 AddRange() 仅增加容量足以准确容纳新项目,则列表最终将被重新调整大小很多次。
我的问题是:据我了解,一次添加一个项目会导致内部容量为List<T>
。每次达到容量时都会加倍,但我不知道如何List<T>.AddRange()
表现。我假设它只增加了足够的容量来容纳新项目,但我找不到任何方法来证实这一点。 MSDN 上关于如何增加容量的描述对于 Add() 和 AddRange() 几乎相同,除了对于 AddRange 它说如果新计数大于容量则增加容量而不是如果计数已经是与容量相同。
对我来说,这就像使用 AddRange() 添加足够的项目以超过当前容量会导致容量增加,其方式与使用 Add() 超过当前容量的方式相同。
因此,将使用 List<T>.AddRange()
添加项目在一个大到足以超过当前容量的 block 中导致容量增加仅足以容纳新项目,还是会导致容量翻倍?还是它做了我什至没有考虑过的其他事情?
希望这在没有任何代码示例的情况下足够清楚,因为这是一个关于如何 List<T>
的普遍问题。已实现,但如果没有,我会添加任何可以使我的问题更清楚的内容。
如前所述,我已阅读 MSDN 文档,但找不到明确的答案。我也在这里搜索过任何类似的问题,但没有找到任何问题,但如果有遗漏的问题,请指出!
最佳答案
只要集合通过 AddRange
参数实现ICollection<T>
数组大小只增加一次:
ICollection<T> collection2 = collection as ICollection<T>;
if (collection2 != null)
{
int count = collection2.Count;
if (count > 0)
{
this.EnsureCapacity(this._size + count);
// (...)
否则标准枚举和Insert
完成每个元素的方法调用:
}
else
{
using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
while (enumerator.MoveNext())
{
this.Insert(index++, enumerator.Current);
}
}
}
编辑
查看EnsureCapacity
方法:
private void EnsureCapacity(int min)
{
if (this._items.Length < min)
{
int num = (this._items.Length == 0) ? 4 : (this._items.Length * 2);
if (num > 2146435071)
{
num = 2146435071;
}
if (num < min)
{
num = min;
}
this.Capacity = num;
}
}
它将数组大小增加 Max(old_size * 2, min)
, 因为它是用 min = old_size + count
调用的AddRange
之后的最终数组大小call 将设置为 Max(old_size * 2, old_size + count)
- 它会警惕电流 List<T>
使用 AddRange
添加的集合的大小和大小方法。
关于c# - 使用 AddRange() 时如何增加 List<T> 的内部数组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18573115/