惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园_首页
Microsoft Security Blog
Microsoft Security Blog
云风的 BLOG
云风的 BLOG
B
Blog
The Register - Security
The Register - Security
L
LangChain Blog
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
N
Netflix TechBlog - Medium
F
Full Disclosure
The GitHub Blog
The GitHub Blog
Recorded Future
Recorded Future
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
Blog — PlanetScale
Blog — PlanetScale
Jina AI
Jina AI
美团技术团队
宝玉的分享
宝玉的分享
Hugging Face - Blog
Hugging Face - Blog
阮一峰的网络日志
阮一峰的网络日志
G
Google Developers Blog
大猫的无限游戏
大猫的无限游戏
S
SegmentFault 最新的问题
D
DataBreaches.Net
Martin Fowler
Martin Fowler
H
Hackread – Cybersecurity News, Data Breaches, AI and More
Google DeepMind News
Google DeepMind News
WordPress大学
WordPress大学
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - Franky
The Cloudflare Blog
博客园 - 【当耐特】
U
Unit 42
月光博客
月光博客
T
The Blog of Author Tim Ferriss
博客园 - 叶小钗
博客园 - 聂微东
I
InfoQ
B
Blog RSS Feed
Apple Machine Learning Research
Apple Machine Learning Research
Cyberwarzone
Cyberwarzone
V
V2EX
S
Securelist
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
S
Security @ Cisco Blogs
PCI Perspectives
PCI Perspectives
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
H
Heimdal Security Blog
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
The Hacker News
The Hacker News
D
Darknet – Hacking Tools, Hacker News & Cyber Security
T
Tor Project blog

博客园 - 飘渺峰

一致性Hash算法 .net Parallel并行使用注意事项 析构函数和Dispose方法的区别 查看SQLServer的最大连接数 Hash算法-CityHash算法 Sunday算法--C#版 KMP算法--C#版 BoyerMoore(BM)算法--C# HostFileChangeMonitor [转]软件项目管理总体流程设计 全排列和组合算法 生活 负载均衡算法--C#版 结束进程的方法forceStopPackage 【转】OAUTH协议简介 SQL Server FOR XML PATH 语句的应用 nlog轻量级日志组件 反射加载程序集的几个方法的区别 windows 下TCP最大连接数
Hash算法
飘渺峰 · 2013-12-15 · via 博客园 - 飘渺峰

 高性能的Hash算法对我们的应用程序无疑是至关重要的。以下几种Hash的性能很不俗,记录在这里。

1. MurMurHash算法

  MurmurHash 是一种非加密哈希函数,适用于一般的哈希检索操作。 由Austin Appleby在2008年发明,并出现了多个变种,都已经发布到了公有领域(public domain)。与其它流行的哈希函数相比,对于规律性较强的key,MurmurHash的随机分布特征表现更良好。

  以下是MurmurHash官方性能图

  

以下是官方的算法实现,随手摘来了。

public class Murmur3
{
    // 128 bit output, 64 bit platform version
 
    public static ulong READ_SIZE = 16;
    private static ulong C1 = 0x87c37b91114253d5L;
    private static ulong C2 = 0x4cf5ad432745937fL;
 
    private ulong length;
    private uint seed; // if want to start with a seed, create a constructor
    ulong h1;
    ulong h2;
 
    private void MixBody(ulong k1, ulong k2)
    {
        h1 ^= MixKey1(k1);
 
        h1 = h1.RotateLeft(27);
        h1 += h2;
        h1 = h1 * 5 + 0x52dce729;
 
        h2 ^= MixKey2(k2);
 
        h2 = h2.RotateLeft(31);
        h2 += h1;
        h2 = h2 * 5 + 0x38495ab5;
    }
 
    private static ulong MixKey1(ulong k1)
    {
        k1 *= C1;
        k1 = k1.RotateLeft(31);
        k1 *= C2;
        return k1;
    }
 
    private static ulong MixKey2(ulong k2)
    {
        k2 *= C2;
        k2 = k2.RotateLeft(33);
        k2 *= C1;
        return k2;
    }
 
    private static ulong MixFinal(ulong k)
    {
        // avalanche bits
 
        k ^= k >> 33;
        k *= 0xff51afd7ed558ccdL;
        k ^= k >> 33;
        k *= 0xc4ceb9fe1a85ec53L;
        k ^= k >> 33;
        return k;
    }
 
    public byte[] ComputeHash(byte[] bb)
    {
        ProcessBytes(bb);
        return Hash;
    }
 
    private void ProcessBytes(byte[] bb)
    {
        h1 = seed;
        this.length = 0L;
 
        int pos = 0;
        ulong remaining = (ulong)bb.Length;
 
        // read 128 bits, 16 bytes, 2 longs in eacy cycle
        while (remaining >= READ_SIZE)
        {
            ulong k1 = bb.GetUInt64(pos);
            pos += 8;
 
            ulong k2 = bb.GetUInt64(pos);
            pos += 8;
 
            length += READ_SIZE;
            remaining -= READ_SIZE;
 
            MixBody(k1, k2);
        }
 
        // if the input MOD 16 != 0
        if (remaining > 0)
            ProcessBytesRemaining(bb, remaining, pos);
    }
 
    private void ProcessBytesRemaining(byte[] bb, ulong remaining, int pos)
    {
        ulong k1 = 0;
        ulong k2 = 0;
        length += remaining;
 
        // little endian (x86) processing
        switch (remaining)
        {
            case 15:
                k2 ^= (ulong)bb[pos + 14] << 48; // fall through
                goto case 14;
            case 14:
                k2 ^= (ulong)bb[pos + 13] << 40; // fall through
                goto case 13;
            case 13:
                k2 ^= (ulong)bb[pos + 12] << 32; // fall through
                goto case 12;
            case 12:
                k2 ^= (ulong)bb[pos + 11] << 24; // fall through
                goto case 11;
            case 11:
                k2 ^= (ulong)bb[pos + 10] << 16; // fall through
                goto case 10;
            case 10:
                k2 ^= (ulong)bb[pos + 9] << 8; // fall through
                goto case 9;
            case 9:
                k2 ^= (ulong)bb[pos + 8]; // fall through
                goto case 8;
            case 8:
                k1 ^= bb.GetUInt64(pos);
                break;
            case 7:
                k1 ^= (ulong)bb[pos + 6] << 48; // fall through
                goto case 6;
            case 6:
                k1 ^= (ulong)bb[pos + 5] << 40; // fall through
                goto case 5;
            case 5:
                k1 ^= (ulong)bb[pos + 4] << 32; // fall through
                goto case 4;
            case 4:
                k1 ^= (ulong)bb[pos + 3] << 24; // fall through
                goto case 3;
            case 3:
                k1 ^= (ulong)bb[pos + 2] << 16; // fall through
                goto case 2;
            case 2:
                k1 ^= (ulong)bb[pos + 1] << 8; // fall through
                goto case 1;
            case 1:
                k1 ^= (ulong)bb[pos]; // fall through
                break;
            default:
                throw new Exception("Something went wrong with remaining bytes calculation.");
        }
 
        h1 ^= MixKey1(k1);
        h2 ^= MixKey2(k2);
    }
 
    public byte[] Hash
    {
        get
        {
            h1 ^= length;
            h2 ^= length;
 
            h1 += h2;
            h2 += h1;
 
            h1 = Murmur3.MixFinal(h1);
            h2 = Murmur3.MixFinal(h2);
 
            h1 += h2;
            h2 += h1;
 
            var hash = new byte[Murmur3.READ_SIZE];
 
            Array.Copy(BitConverter.GetBytes(h1), 0, hash, 0, 8);
            Array.Copy(BitConverter.GetBytes(h2), 0, hash, 8, 8);
 
            return hash;
        }
    }
}

 使用方法:

public static class IntHelpers
{
    public static ulong RotateLeft(this ulong original, int bits)
    {
        return (original << bits) | (original >> (64 - bits));
    }
 
    public static ulong RotateRight(this ulong original, int bits)
    {
        return (original >> bits) | (original << (64 - bits));
    }
 
    unsafe public static ulong GetUInt64(this byte[] bb, int pos)
    {
        // we only read aligned longs, so a simple casting is enough
        fixed (byte* pbyte = &bb[pos])
        {
            return *((ulong*)pbyte);
        }
    }
}