字典性能提升

时间:2012-10-15 10:11:56

标签: c# dictionary

我正在努力改进一段时间写的代码。该功能对系统的核心功能非常重要,因此我对大刀阔斧的改革持谨慎态度。

我正在使用字典来保存对象

Dictionary<Node, int> dConnections

对象Node本身就是一个包含许多属性和一些列表的复杂对象。 这个字典可以变得非常大,可容纳100个或更多条目。

目前正在检查字典是否包含类似

的节点
dConnections.ContainsKey(Node)

所以我假设(为了检查这个节点是否在字典中),字典必须检查整个节点及其属性是否与字典中的节点匹配(它将继续迭代字典,直到它找到匹配)这会对性能产生重大影响吗?

我最好不要在字典中使用对象而是使用对象ID。

2 个答案:

答案 0 :(得分:5)

.NET字典是Inside中的哈希表。这意味着如果Node没有覆盖GetHashCode和Equals方法,当您调用ContainsKey时,它将匹配:

免责声明:这是一个总结。事情有点复杂。请不要叫我名字,因为我过于简单了。

  1. Node对象的ref地址的哈希码的分区。分区数取决于散列表的桶数(取决于字典中的键总数)
  2. 如果多个节点位于同一个存储桶中,则为确切的引用地址。
  3. 此算法非常有效。如果你说字典中有100个或更多条目,那就不是“很多”了。这是一些。

    这也意味着Node对象的内容与ContainsKey匹配的方式无关。它将与完全相同的引用匹配,并且仅针对此引用。

    如果您自己实现GetHashCode和Equals,请注意当实例属性更改(不可变)时,这些方法返回值不应更改。否则你很可能在错误的存储桶中获取密钥,因此完全无法访问(无需枚举整个字典)。

答案 1 :(得分:3)

  

它将继续遍历字典,直到找到匹配

不,字典通过迭代所有节点找不到匹配项;首先获取哈希码,并用于将候选者限制为一个,可能是几个(取决于你的哈希方法有多好,以及桶大小)

  

所以我假设(为了检查这个节点是否在字典中),字典必须检查整个节点及其属性是否与字典中的节点匹配

不,对于每个候选人,它首先检查哈希码,这是一个快捷方式,以检测 -equality vs 可能的 -equality非常快速

所以关键在于:您的Node散列方法,即GetHashCode。如果这很复杂,那么另一个技巧是在你第一次需要它时将其缓存,即

int cachedHashCode;
public override int GetHashCode() {
    if(cachedHashCode == 0) {
       cachedHashCode = /* some complex code here */
       if(cachedHashCode == 0) {
           cachedHashCode = -45; // why not... just something non-zero
       }
    }
    return cachedHashCode;
}

请注意 仍然使用Equals,因为最终“它们是相同的”,所以你显然希望Equals尽可能快 - 但Equals将被称为相对较少。