【问题标题】:Why is NameValueCollection.Remove(string key) so slow on large collections?为什么 NameValueCollection.Remove(string key) 在大型集合上如此缓慢?
【发布时间】:2014-06-23 09:05:36
【问题描述】:

我有一种情况,我有大量项目存储在 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&lt;TKey, TValue&gt;的这个版本进行了比较:

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);
}

上面的示例运行得如此之快,它可能是即时的。

那么,为什么在我看来做类似事情的两个不同系列的工作方式却如此不同?

【问题讨论】:

    标签: c# performance collections


    【解决方案1】:

    感谢BCL Reference Source,我能够确定为什么NameValueCollection.Remove() 方法需要这么长时间。下面是被调用的NameObjectCollectionBase.BaseRemove()方法的sn-p代码:

    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&lt;TKey, TValue&gt; 用作哈希表,这意味着按键查找非常快。而NameValueCollection 看起来更像是一个跟踪索引和键的数组。通过一次删除数十万个键,此方法实际上将无数次循环整个内部数组以找到要删除的正确值!

    最后,我将代码更改为不使用NameValueCollection,而是使用Dictionary&lt;TKey, TValue&gt;

    【讨论】:

    • 您在提出问题的同时添加了一个答案。如果您已经准备好答案,那么首先询问的目的是什么?
    • +1。 @Tarec - 我认为这是一个非常合理的问题/答案 - 有类似的问题,如 NVC vs Dictionary,但没有一个涉及性能部分。可以回答自己的问题,如果没有更好的答案,甚至接受它...... - 我也会把答案作为“社区维基”来减少争论。
    • 我不反对将其标记为答案。我反对在问题发布的同一分钟内这样做,而他假装有一个实际上他已经解决的问题。关于“为什么方法 x 比方法 y 快”的问题,您总是可以回答:反编译和比较。
    • 因为根据 StackOverflow it is OK to answer your own question - 为什么在问题表单中还有这样的复选框?我只是为其他人提供信息,因为这给我带来了可能对其他人有帮助的问题。
    • @AlexeiLevenkov 我不认为将答案标记为社区 Wiki,因为我以前从未这样做过。很高兴这样做
    猜你喜欢
    • 2013-06-12
    • 2011-02-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-04-22
    • 2013-06-16
    • 1970-01-01
    • 2013-10-19
    相关资源
    最近更新 更多