0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

Linux内核中的hash与bucket

Q4MP_gh_c472c21 来源:未知 作者:胡薇 2018-06-12 14:53 次阅读

哈希表(Hashtable)又称为“散列”,Hashtable是会根据索引键的哈希程序代码组织成的索引键(Key)和值(Value)配对的集合。Hashtable 对象是由包含集合中元素的哈希桶(Bucket)所组成的。而Bucket是Hashtable内元素的虚拟子群组,可以让大部分集合中的搜寻和获取工作更容易、更快速。

哈希函数(Hash Function)为根据索引键来返回数值哈希程序代码的算法。索引键(Key)是被存储对象的某些属性值(Value)。当对象加入至 Hashtable时,它存储在与对象哈希程序代码相符的哈希程序代码相关的Bucket中。当在Hashtable内搜寻值时,哈希程序代码会为该值产生,并且会搜寻与该哈希程序代码相关的Bucket。例如,student和teacher会放在不同的Bucket中,而dog和god会放在相同的 Bucket中。所以当索引键是唯一从Hashtable获取元素的性能时表现会较好。Hash的四大优点如下所示。

·事先不需要排序。

·搜寻速度与数据多少无关。

·数字签名的密码技术保密性(Security)高。

·可做数据压缩(Data Compression),以节省空间。

Linux内核里的哈希表应用非常广泛,PHP内核里大部分语言特性也是基于哈希表实现的。为什么哈希表能这么神通广大?哈希表能够实现高效的数据存储和查找,而存储和查找是编程中应用最广泛的两个操作。

Linux内核里的哈希表

读过Linux内核源码的人可能都会发现,其中并没有太多复杂的数据结构,作为基础数据结构的双向链表(list)和基于list实现的hash表占据了绝大部分数据结构。内核为什么会大量使用这两种数据结构呢?围绕这个问题(主要是hash表),我将以自己的理解揣摩一下其意图。

首先,这两种数据结构都十分简单,简单包括理解起来简单和使用起来简单两方面内容。这也意味着代码的可读性和可维护性都比其他复杂的数据结构要好,出现bug的风险也较低。从哲学上来讲,这也符合K.I.S.S.条款。

其次,内核是一个比较讲究性能的软件,为了程序设计和维护的简单性而失掉性能,这究竟是不是算得不偿失呢?我们是不是应该将天平更加偏向于性能?已经记不起是在哪里听说过,很多商业的路由软件都是基于二叉树的数据结构来存储路由项,以求得其路由查找的时间复杂度为log(n),并且他批评Linux的路由项组织为hash表,致使性能不佳,不适合商业。确实有一定道理,可仔细分析,hash表的性能真的比二叉树差么?二叉树的插入和删除某一项的时间复杂度都为log(n);hash表插入和删除的时间复杂度最好为O(1),最差为O(n),如果选取的表项(m)足够多,且hash函数足够好的话,其时间复杂度为O(n/m)(当m<=n时)。当m > n / log(n)的时候,hash表的平均表现就比二叉树要好;且当m>=n时,其时间复杂度趋近于O(1)。m的值可以做成可调整的,这也正显示了内核的可定制性。不过,不要盲目乐观,这一切都是以一个足够好的hash函数为前期的。

hash函数的优劣

如何判定一个hash函数的好坏呢?

hash的中文意思是“散列”,可解释为:分散排列。一个好的hash函数应该做到对所有元素平均分散排列,尽量避免或者降低他们之间的冲突(Collision)。有必要再次提醒大家的是,hash函数的选择必须慎重,如果不幸所有的元素之间都产生了冲突,那么hash表将退化为链表,其性能会大打折扣,时间复杂度迅速降为O(n),绝对不要存在任何侥幸心理,因为那是相当危险的。历史上就出现过利用Linux内核hash函数的漏洞,成功构造出大量使hash表发生碰撞的元素,导致系统被DoS,所以目前内核的大部分hash函数都有一个随机数作为参数进行掺杂,以使其最后的值不能或者是不易被预测。这又对 hash函数提出了第二点安全方面的要求:hash函数最好是单向的,并且要用随机数进行掺杂。提到单向,你也许会想到单向散列函数md4和md5,很不幸地告诉你,他们是不适合的,因为hash函数需要有相当好的性能。

一筹莫展了吧?谁叫你又想闭门造车了!还是看看前辈们是如何做的,充分发扬拿来主义的精神,我又称这种做法为“不战而屈人之兵”,这难道不是兵家之上上策么?Linux内核里面用的jhash是一个久经考验,并被实践证明经得起考验的hash函数,可以CPMS(Copy Paste Modify Save)之。Jhash的作者Bob Jenkins在其网站上还公布了诸如针对能预知的数据进行hash的hash函数--完美(perfect)hash函数等一系列其他hash函数,看客们可以选择之,如果有兴趣继续钻研,也可以踏在他们的肩膀上。

什么是bucket

bucket的英文解释:

Hash table lookup operations are often O(n/m) (where n is the number of objects in the table and m is the number of buckets), which is close to O(1), especially when the hash function has spread the hashed objects evenly through the hash table, and there are more hash buckets than objects to be stored.

可以这样理解:

一个HASH的结果所对应的地址可存放两个BUCKET。可解决HASH冲突。

·要存数据时,第一次HASH到这里,在第一个BUCKET存放一个数据。

·要存数据时,当第二次因某些原因HASH到这里时,在第二个BUCKET存放另一个数据。

一个由5个buckets组成的哈希表,里面有7个元素:

linux的hash函数hash_long等,用了golden ratio来计算。因为桶(bits)的数量需要由hash函数和对冲突的期望来决定,那么对于hash_long这样的hash函数,我们怎么确定桶的数量呢?

一般情况下都是自己根据数据特性来考虑使用的 hash 算法,不是千篇一律咬死一个不放。

比如存放 IP 地址的 hash table,用一个 65536 的桶就很好,把 IP 的后 16bit 作为 key。这种方法绝对比 hash_long、jhash 等函数的碰撞率低。

其实就是这个界和性能的折中。我可以取我问题空间的最大值。这样肯定能保证键值分散。但是这样会浪费很多空间。然而取得太小,又影响查找效率。感觉还是要在试验中进行测试。而且个人觉得,hash比其他搜索的数据结构灵活的地方就是它的可定制性。可以根据具体情况调整,以达到最优的效果。

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • Linux
    +关注

    关注

    87

    文章

    11285

    浏览量

    209265
  • Hash
    +关注

    关注

    0

    文章

    32

    浏览量

    13195
收藏 人收藏

    评论

    相关推荐

    Linux内核container_of原理详解

    Linux内核中经常可见container_of的身影,它在实际驱动的编写也是广泛应用。
    发表于 07-14 15:19 309次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b><b class='flag-5'>中</b>container_of原理详解

    Linux内核教程

    本章学习目标掌握LINUX内核版本的含义理解并掌握进程的概念掌握管道的概念及实现了解内核的数据结构了解LINUX内核的算法掌握
    发表于 04-10 16:59 0次下载

    hash表的实现原理

    软件开发,一个hash表相当于把n个key随机放入到b个bucket,以实现n个数据在b个单位空间的存储。 我们发现hash
    发表于 09-28 14:31 0次下载
    <b class='flag-5'>hash</b>表的实现原理

    Linux内核配置系统详解

    随着 Linux 操作系统的广泛应用,特别是 Linux 在嵌入式领域的发展,越来越多的人开始投身到 Linux 内核级的开发。面对日益庞
    发表于 11-01 15:45 4次下载

    linux内核是什么_linux内核学习路线

    Linux内核是一个操作系统(OS)内核,本质上定义为类Unix。它用于不同的操作系统,主要是以不同的Linux发行版的形式。Linux
    发表于 09-16 15:49 2632次阅读

    linux内核参数设置_linux内核的功能有哪些

    本文主要阐述了linux内核参数设置及linux内核的功能。
    发表于 09-17 14:40 1371次阅读
    <b class='flag-5'>linux</b><b class='flag-5'>内核</b>参数设置_<b class='flag-5'>linux</b><b class='flag-5'>内核</b>的功能有哪些

    最硬核的Linux内核文章

    来源 :头条号@Linux学习教程,冰凌块儿 01 前言 本文主要讲解什么是Linux内核,以及通过多张图片展示Linux内核的作用与功能,
    的头像 发表于 10-19 17:46 2112次阅读
    最硬核的<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>文章

    快速理解什么是Linux内核以及Linux内核的内容

    01 前言 本文主要讲解什么是Linux内核,以及通过多张图片展示Linux内核的作用与功能,以便于读者能快速理解什么是Linux
    的头像 发表于 10-21 12:02 4283次阅读
    快速理解什么是<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>以及<b class='flag-5'>Linux</b><b class='flag-5'>内核</b>的内容

    linux内核的driver_register介绍

    linux内核注册驱动由driver_register()完成。它将驱动程序的信息添加到内核的驱动程序列表,使得内核能够在需要时与该驱动
    的头像 发表于 07-14 09:17 2815次阅读
    <b class='flag-5'>linux</b><b class='flag-5'>内核</b><b class='flag-5'>中</b>的driver_register介绍

    Linux内核分析 端口哈希桶

    是用来封装各种协议的绑定哈希表,具体定义如下所示,这个结构体在[Linux内核角度分析服务器Listen细节中介绍过,具体地,struct inet_bind_hashbcket是bind相关的哈希桶
    的头像 发表于 07-31 11:03 766次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b>分析 端口哈希桶

    linux内核源代码详解

     在安装好的Linux系统内核的源代码位于/ust/src/linux.如果是从GNU网站下载的Linux
    发表于 09-06 17:01 4次下载

    hash算法在FPGA的实现(1)

    在FPGA的设计,尤其是在通信领域,经常会遇到hash算法的实现。hash算法在FPGA的设计,它主要包括2个部分,第一个就是如何选择一个好的h
    的头像 发表于 09-07 17:01 1201次阅读
    <b class='flag-5'>hash</b>算法在FPGA<b class='flag-5'>中</b>的实现(1)

    hash算法在FPGA的实现(2)

    在前面的文章hash算法在FPGA的实现(一)——hash表的组建,记录了关于hash表的构建,这里记录另外一个话题,就是
    的头像 发表于 09-07 17:02 788次阅读
    <b class='flag-5'>hash</b>算法在FPGA<b class='flag-5'>中</b>的实现(2)

    使用 PREEMPT_RT 在 Ubuntu 构建实时 Linux 内核

    盟通技术干货构建实时Linux内核简介盟通技术干货Motrotech如果需要在Linux实现实时计算性能,进而有效地将Linux转变为RT
    的头像 发表于 04-12 08:36 2369次阅读
    使用 PREEMPT_RT 在 Ubuntu <b class='flag-5'>中</b>构建实时 <b class='flag-5'>Linux</b> <b class='flag-5'>内核</b>

    Linux内核的页面分配机制

    Linux内核是如何分配出页面的,如果我们站在CPU的角度去看这个问题,CPU能分配出来的页面是以物理页面为单位的。也就是我们计算机中常讲的分页机制。本文就看下Linux
    的头像 发表于 08-07 15:51 272次阅读
    <b class='flag-5'>Linux</b><b class='flag-5'>内核</b><b class='flag-5'>中</b>的页面分配机制