首页 新闻 会员 周边 捐助

C#中计算字符串Hash值速度最快的方法是什么

0
悬赏园豆:100 [已解决问题] 解决于 2013-10-12 08:41

应用场景:在使用memcached时,有些作为key的字符串中会出现中文,需要为该字符串生成Hash值,然后将该hash值作为缓存key。

不考虑使用Enyim.Caching.Memcached.SHA1KeyTransformer(详见memcached对中文key的支持),因为这会对所有key进行Hash计算,而我们只需对会出现中文的key进行Hash计算。

目前我们使用的方法是直接调用.NET类库的String.GetHashCode()方法。

想在博问中问一下有没有比String.GetHashCode()计算速度更快的方法。

ILSpy查看到的String.GetHasCode()的实现代码如下:

public unsafe override int GetHashCode()
{
    if (HashHelpers.s_UseRandomizedStringHashing)
    {
        return string.InternalMarvin32HashString(this, this.Length, 0L);
    }
    IntPtr arg_25_0;
    IntPtr expr_1C = arg_25_0 = this;
    if (expr_1C != 0)
    {
        arg_25_0 = (IntPtr)((int)expr_1C + RuntimeHelpers.OffsetToStringData);
    }
    char* ptr = arg_25_0;
    int num = 5381;
    int num2 = num;
    char* ptr2 = ptr;
    int num3;
    while ((num3 = (int)(*(ushort*)ptr2)) != 0)
    {
        num = ((num << 5) + num ^ num3);
        num3 = (int)(*(ushort*)(ptr2 + (IntPtr)2 / 2));
        if (num3 == 0)
        {
            break;
        }
        num2 = ((num2 << 5) + num2 ^ num3);
        ptr2 += (IntPtr)4 / 2;
    }
    return num + num2 * 1566083941;
}
问题补充:

Enyim.Caching.Memcached.SHA1KeyTransformer中是这样实现的:

public override string Transform(string key)
{
    var sh = new SHA1Managed();
    byte[] data = sh.ComputeHash(Encoding.Unicode.GetBytes(key))
    return Convert.ToBase64String(data, Base64FormattingOptions.None);
}
dudu的主页 dudu | 高人七级 | 园豆:30939
提问于:2013-09-29 14:22
< >
分享
最佳答案
1

不同字符串 也可能生成相同的hashcode,这就是hash碰撞。

Dictionary在key的hash值碰撞时,是通过链表来解决的。

取值的时候,先通过key的hash值找到链表。然后遍历链表,用构造函数传入的IEqualityComparer<TKey> 来找到Equals key的对象。

原生的GetHashCode方法主要考虑的是分布均匀,即使几个差不多的字符串,hash值也能均匀分布。修改算法可以提高hash值得计算速度,但是对于有规律的字符串,分布未必有原生的均匀。造成对hash表的查找性能降低,反而得不偿失。毕竟hash值基本上就是为hash表准备的。

收获园豆:80
刀是什么样的刀 | 小虾三级 |园豆:910 | 2013-10-11 21:45

谢谢!学习了!

另外,分享一篇文章:从头到尾彻底解析Hash表算法

dudu | 园豆:30939 (高人七级) | 2013-10-12 08:42
其他回答(5)
0

为什么不用Guid.NewGuid();生成的值作为Key呢?这个更快更方便。不知道对否?

BLUESMAN | 园豆:213 (菜鸟二级) | 2013-09-29 15:37
0

还有一个问题String.GetHashCode()会有重复值。。

收获园豆:10
李永京 | 园豆:3114 (老鸟四级) | 2013-09-29 16:26

字符串不长的话,重复的概率很小吧?

支持(0) 反对(0) dudu | 园豆:30939 (高人七级) | 2013-09-29 16:33

@dudu: 重复值概率很大了。不过无所谓。重复就重复,因为字符串相同,所以重复了也表示一个意思。

支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-09-29 16:41

@imfunny: 字符串相同?

支持(0) 反对(0) dudu | 园豆:30939 (高人七级) | 2013-09-29 16:46

@dudu: 对字符串相同gethashcode肯定也相同,同理。如果hash值相同了,字符串即使新的,也指向到以前的字符串。这个貌似之前一直被人说为gethashcode的一个坑。

支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-09-29 16:48

@imfunny: 这样用作缓存key还是有些问题

支持(0) 反对(0) dudu | 园豆:30939 (高人七级) | 2013-09-29 16:54

@dudu: 这个上面有过讨论。http://bbs.csdn.net/topics/320009239  第72楼的总结。还有一些验证重复的方法。

反正肯定会有重复,字符串祝贺大于了int的范围。

支持(0) 反对(0) ````` | 园豆:14268 (专家六级) | 2013-09-29 17:05

@imfunny: 嗯,int类型的限制

支持(0) 反对(0) dudu | 园豆:30939 (高人七级) | 2013-09-29 17:08
0

将中文转成BASE64的编码方式作为key使用,这样速度应该也是可以的,而且也不会导致重复。

不过具体的时间比较就得专门去测试一下了

诶碧司 | 园豆:1912 (小虾三级) | 2013-09-29 23:32
0

上面大部分人都不懂什么叫Hash函数

钧梓昊逑 | 园豆:945 (小虾三级) | 2013-09-30 10:27
0

貌似很不建议使用的就是String.GetHashCode()了吧,记得有哪里说过,不同版本的.net framework 生成的hashcode是不一样的,这是灾难性的事情啊。

acles | 园豆:252 (菜鸟二级) | 2014-08-03 22:49
清除回答草稿
   您需要登录以后才能回答,未注册用户请先注册