【问题标题】:Dictionary and Caching字典和缓存
【发布时间】:2013-08-27 19:25:30
【问题描述】:

我有一个名为 Color 的类,它实现了以下覆盖:

public override Int32 GetHashCode()
{
    unchecked
    {
        Int32 hash = 23;
        hash = (hash * 37) + m_Changes.GetHashCode();
        hash = (hash * 37) + m_Blue;
        hash = (hash * 37) + m_Green;
        hash = (hash * 37) + m_Random;
        hash = (hash * 37) + m_RandomBlue;
        hash = (hash * 37) + m_RandomGreen;
        hash = (hash * 37) + m_RandomRed;
        hash = (hash * 37) + m_Red;

        return hash;
    }
}

我正在尝试缓存结果以减少计算:

public static Color Average(Color left, Color right, Double weight)
{
    Color value;
    Int32 key = left.GetHashCode() ^ right.GetHashCode() ^ weight.GetHashCode();

    if (!s_Averages.TryGetValue(key, out value))
    {
        Double complement = 100.0 - weight;

        Int32 red = (Int32)(((left.Red * complement) + (right.Red * weight)) / 100.0);
        Int32 green = (Int32)(((left.Green * complement) + (right.Green * weight)) / 100.0);
        Int32 blue = (Int32)(((left.Blue * complement) + (right.Blue * weight)) / 100.0);
        Int32 random = (Int32)(((left.Random * complement) + (right.Random * weight)) / 100.0);
        Int32 randomRed = (Int32)(((left.RandomRed * complement) + (right.RandomRed * weight)) / 100.0);
        Int32 randomGreen = (Int32)(((left.RandomGreen * complement) + (right.RandomGreen * weight)) / 100.0);
        Int32 randomBlue = (Int32)(((left.RandomBlue * complement) + (right.RandomBlue * weight)) / 100.0);

        value = new Color(red, green, blue, randomRed, randomGreen, randomBlue, random, (left.Changes || right.Changes));
        s_Averages.Add(key, value);
    }

    return value;
}

结果不好,因为我在屏幕上绘制平均颜色时得到错误的像素。如果我将该方法恢复为无缓存版本,一切正常:

public static Color Average(Color left, Color right, Double weight)
{
    Double complement = 100.0 - weight;

    Int32 red = (Int32)(((left.Red * complement) + (right.Red * weight)) / 100.0);
    Int32 green = (Int32)(((left.Green * complement) + (right.Green * weight)) / 100.0);
    Int32 blue = (Int32)(((left.Blue * complement) + (right.Blue * weight)) / 100.0);
    Int32 random = (Int32)(((left.Random * complement) + (right.Random * weight)) / 100.0);
    Int32 randomRed = (Int32)(((left.RandomRed * complement) + (right.RandomRed * weight)) / 100.0);
    Int32 randomGreen = (Int32)(((left.RandomGreen * complement) + (right.RandomGreen * weight)) / 100.0);
    Int32 randomBlue = (Int32)(((left.RandomBlue * complement) + (right.RandomBlue * weight)) / 100.0);

    return (new Color(red, green, blue, randomRed, randomGreen, randomBlue, random, (left.Changes || right.Changes)));
}

这只能意味着我使用 GetHashCode 生成的密钥不是唯一的。如何管理这种缓存,为我的颜色平均值获取唯一键?

【问题讨论】:

  • 例如:为什么你认为这是一个合适且唯一的键?:Int32 key = left.GetHashCode() ^ right.GetHashCode() ^ weight.GetHashCode();
  • 嗯,我不这么认为,从这产生了什么......这就是为什么我试图找到一个好的解决方案......
  • 感觉即使有缓存,哈希码计算和字典查找也可能不会让事情快很多(除非你有 很多重复使用的颜色)。你有一个可衡量的瓶颈吗?另外,已经很晚了,所以我可能错了,但是您不能将100.0complementweight 预先划分一次而不是6 次吗? (即便如此,这是一个很小的优化)
  • 问题是我每 50 毫秒使用数百种颜色。渲染工作正常,但一开始,如果我不得不计算我需要用于该帧的所有颜色,一切都会变慢......这就是我试图缓存的原因。预分割是什么意思?

标签: c# .net caching dictionary hashcode


【解决方案1】:

在这种情况下,我认为您不会获得唯一的密钥
但你可以做得更好
如果您左右切换您会得到相同的密钥,则会受到影响。

Int32 key = left.GetHashCode() ^ right.GetHashCode() ^ weight.GetHashCode();
15 ^ 17 ^ 20 == 17 ^ 15 ^ 20

这将减少键冲突

Int32 key = 17*left.GetHashCode() ^ 23*right.GetHashCode() ^ weight.GetHashCode();

更好的是可以使用 UInt64 键

UInt64 key = (((UInt64)left.GetHashCode() << 32) | (UInt64)right.GetHashCode()) ^ ((UInt64)weight.GetHashCode() << 30);

看看你的平均水平。
所有这些颜色都在计算中被转换为 Double 并且有开销。
这必须有多精确?
如果权重和补码是 Int32 会有一些舍入误差,但它会更快。

Int32 iweight = (Int32)(weight*100);   
Int32 icomplement = 10000 - weight;
Int32 red = ((left.Red * icomplement) + (right.Red * iweight)) / 10000;

同样,这会有一些舍入误差,但会更快。

您为什么使用 Int32?
UInt16 或 Byte 就足够了吗?
数学并不快,但会减少记忆。

【讨论】:

  • 如果您能回答我提出的问题,那么我可能会改进答案。
  • 感谢您的回答。您的解决方案明智地减少了我的碰撞,但我仍在经历它们。除了使用 Dictionary 或为键计算 MD5/CRC32 之外,我还有其他选择吗?
  • 我重复“如果您能回答我提出的问题,那么我可能会改进答案”。我当然不推荐元组。不感谢您的 +1
猜你喜欢
  • 1970-01-01
  • 2018-08-27
  • 2012-09-17
  • 2011-10-18
  • 2019-01-29
  • 2018-06-15
  • 2010-09-29
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多