为什么NameValueCollection.Remove(字符串键)在大型集合上如此慢?

时间:2014-05-06 16:22:39

标签: c# performance collections

我的情况是,HttpApplicationState中存储了大量项目,内部使用NameValueCollection来存储键值对。我的意思是大约数十万个字符串项。在这个特殊情况下,我也尝试批量删除密钥(再次,通过密钥从集合中删除大块项目),但我发现这样做很痛苦。

我写了以下样本进行比较。第一个代码示例使用NameValueCollection按键删除所有值:

NameValueCollection collection = new NameValueCollection();

// Setup
for (int i = 0; i < 100000; i++)
{
    collection.Add(i.ToString(), i.ToString());
}

// Remove
for (int i = 0; i < 100000; i++)
{
    collection.Remove(i.ToString());
}

运行这个需要一个年龄(实际上我放弃了,因为它花了太长时间)。然后我将其与使用Dictionary<TKey, TValue>

的此版本进行了比较
Dictionary<int, int> collection = new Dictionary<int, int>();

// Setup
for (int i = 0; i < 100000; i++)
{
    collection.Add(i, i);
}

// Remove
for (int i = 0; i < 100000; i++)
{
    collection.Remove(i);
}

以上样本运行速度非常快,也可能是即时的。

那么为什么我认为做类似事情的两个不同的集合工作方式如此不同呢?

1 个答案:

答案 0 :(得分:2)

感谢BCL Reference Source我能够确定NameValueCollection.Remove()方法花费这么长时间的原因。以下是调用的NameObjectCollectionBase.BaseRemove()方法的代码段:

if (name != null) {
    // remove from hashtable
    _entriesTable.Remove(name);

    // remove from array
    for (int i = _entriesArray.Count-1; i >= 0; i--) {
        if (_keyComparer.Equals(name, BaseGetKey(i)))
            _entriesArray.RemoveAt(i);
    }
}

基本上Dictionary<TKey, TValue>用作哈希表,这意味着按键查找非常快。而NameValueCollection似乎更像是一个跟踪索引和键的数组。通过一次删除数十万个键,这个方法实际上会无数次遍历整个内部数组,以找到要删除的正确值!

最后,我将代码更改为不使用NameValueCollection而是使用Dictionary<TKey, TValue>代替。