【问题标题】:performance of two Dictionary retrievals vs one key retrieval两次字典检索与一键检索的性能
【发布时间】:2014-01-03 18:27:44
【问题描述】:

我有这个遗留代码,其中通常存在字符串字典到字符串字典到某个对象的这种模式。

Dictionary<string, Dictionary<string, someobject>>

对象的检索总是基于两次 TryGetValue

Dictionary<string, Dictionary<string, Dealer>> dicDealers ...

if (dicDealers.TryGetValue(lab, out dealers))
  dealers.TryGetValue(dealerNumber, out dealer);

现在我认为将两个字符串键组合成一个具有两个字符串成员的键结构应该更有效,以便一次性检索对象。所以我创建了一个 Key 结构,它覆盖 GetHashCode 和 Equals,计算机器人关键成员的哈希值。

public struct Key<T>
{
    private T mKey1;
    private T mKey2;

    public Key(T t, T u)
    {
        mKey1 = t;
        mKey2 = u;
    }

    public override bool Equals(object obj)
    {
        if (obj == null) return false;

        Key<T> rhs = (Key<T>)obj;

        return mKey1.Equals(rhs.mKey1) && mKey2.Equals(rhs.mKey2);
    }

    public override int GetHashCode()
    {
        int hash = 17;

        hash = ((hash << 5) - hash) + mKey1.GetHashCode();
        hash = ((hash << 5) - hash) + mKey2.GetHashCode();
        return hash;
    }
}

现在您可以立即完成。

Key<string> key = new Key<string>(lab, dealerNumber);

if (dicDealers.TryGetValue(key, out someobject))
{
...
}

我认为它应该更快,但事实证明这两种方式都一样快。这个怎么可能?我可以做些什么来让第二种技术运行得更快吗?

【问题讨论】:

  • 是否存在性能问题?如果不是,则优先考虑可读性,将 Directory 封装在具有检索项目方法的新类中可能是有意义的,因此您不必使用 TryGetValue 调用乱扔代码。
  • 这也是为了可读性,是的,但这不是问题
  • 那是什么问题?
  • 您如何验证这两种方式“差不多快”?
  • 我注意到,使用new key = key1 + "-" + key2 不是保留多个嵌套字典,而是易于维护。您必须仔细选择分隔符。

标签: c# .net


【解决方案1】:

您正在尝试改进一种已摊销 O(1) 复杂度的方法。这是一项艰巨的任务,您永远无法比 O(1) 更高效,没有任何算法是 O(1/x)。

你唯一可以改进的是哦。字典的 Oh 取决于 GetHashCode() 的成本以及散列码的分布情况。你又在打一场很难取胜的战斗。 String.GetHashCode() 是用hand-optimized code 编写的,并产生一个非常 好的散列。

事实上,您并没有让您的 GetHashCode() 更高效,它的成本与原始版本中的两次 GetHashCode() 调用相同。所以是的,您当然应该期望您的版本会花费尽可能多的时间。

尝试制作更好的版本是一个漫长的过程。你必须对字符串有特殊的了解,比如知道一个好的散列只需要第一个字符,这样你就可以采取捷径计算整个字符串的散列。这不常见而且有点危险,散列码分布不佳是有害的。最重要的是,没有必要。你犯的核心错误是试图改进不需要改进的代码。只有在分析器告诉您 TryGetValue() 是关键代码时才考虑这样做。

【讨论】:

  • 我省略了这部分,因为它也是为了可读性。但是好的,优化 O(1) 非常困难是的
猜你喜欢
  • 2017-01-07
  • 2018-09-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-25
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多