<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Redis on Kingcanfish 的小星球 🪐</title>
        <link>https://blog.gxy.plus/tags/redis/</link>
        <description>Recent content in Redis on Kingcanfish 的小星球 🪐</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>zh</language>
        <copyright>Kingcanfish. All rights reserved.</copyright>
        <lastBuildDate>Sat, 30 May 2020 21:43:24 +0800</lastBuildDate><atom:link href="https://blog.gxy.plus/tags/redis/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Go和Redis中的Hash</title>
            <link>https://blog.gxy.plus/posts/hashingoandredis/</link>
            <pubDate>Sat, 30 May 2020 21:43:24 +0800</pubDate>
            <guid>https://blog.gxy.plus/posts/hashingoandredis/</guid>
            <description>&lt;p&gt;之前看  &lt;em&gt;Redis设计与实现&lt;/em&gt;  的时候看了一些字典的底层实现是基于hash表的，然后这几天看到Golang 的map 时也是基于hash表的，&lt;del&gt;实际上大部分开发语言的map数据类型基本上都是基于hash表的&lt;/del&gt; 所以就打算写一篇比较垃圾的博客&lt;del&gt;集百家之长&lt;/del&gt;把这两个东西的底层实现放在一块讲了，加深下自己的映像。（由于水平不够，如果有错误还请一起探讨指出）&lt;/p&gt;&#xA;&lt;h2 id=&#34;hash&#34;&gt;Hash&#xA;&lt;/h2&gt;&lt;p&gt;&lt;a class=&#34;link&#34; href=&#34;https://baike.baidu.com/item/%e6%95%a3%e5%88%97%e8%a1%a8/10027933&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;散列表&lt;/a&gt;（Hash table，也叫哈希表），是根据关键码值(Key value)而直接进行访问的&lt;a class=&#34;link&#34; href=&#34;https://baike.baidu.com/item/%e6%95%b0%e6%8d%ae%e7%bb%93%e6%9e%84/1450&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;数据结构&lt;/a&gt;。也就是说，它通过把关键码值映射到表中一个位置来访问记录，以加快查找的速度。这个映射函数叫做&lt;a class=&#34;link&#34; href=&#34;https://baike.baidu.com/item/%e6%95%a3%e5%88%97%e5%87%bd%e6%95%b0/2366288&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;散列函数&lt;/a&gt;，存放记录的&lt;a class=&#34;link&#34; href=&#34;https://baike.baidu.com/item/%e6%95%b0%e7%bb%84/3794097&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;数组&lt;/a&gt;叫做&lt;a class=&#34;link&#34; href=&#34;https://baike.baidu.com/item/%e6%95%a3%e5%88%97%e8%a1%a8/10027933&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;散列表&lt;/a&gt;。&lt;/p&gt;&#xA;&lt;p&gt;给定表M，存在函数f(key)，对任意给定的关键字值key，代入函数后若能得到包含该关键字的记录在表中的地址，则称表M为哈希(Hash）表，函数f(key)为哈希(Hash) 函数。&lt;/p&gt;&#xA;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;摘自百度百科&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;h2 id=&#34;redis-中的-hash&#34;&gt;Redis 中的 Hash&#xA;&lt;/h2&gt;&lt;h3 id=&#34;结构图&#34;&gt;结构图&#xA;&lt;/h3&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;图源 &lt;em&gt;Redis 设计与实现&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;h3 id=&#34;hash-表&#34;&gt;Hash 表&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Redis&lt;/code&gt; 中的hash表由以下结构定义:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dictht&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;dictEntry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;**&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;table&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//哈希桶数组&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;size&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//哈希表的大小,就是 哈希桶数组长度&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;sizemask&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//哈希表大小掩码，数值上为size-1，用于计算索引值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;unsigned&lt;/span&gt; &lt;span class=&#34;kt&#34;&gt;long&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;used&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//哈希表已有的节点数量&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;table 为一个 数组，每个数组里都存放着一个一组指向 &lt;code&gt;dict.h/dictEntry&lt;/code&gt;  结构的指针，然后每一个 &lt;code&gt;dicEntry&lt;/code&gt;  结构 保存着 一个键值对，这个结构 也称为&lt;code&gt;HashBucket&lt;/code&gt; ，哈希桶&lt;/li&gt;&#xA;&lt;li&gt;used 表示 这个 hash表中现在已有的键值对的数量&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;hash-表节点哈希桶&#34;&gt;Hash 表节点（哈希桶）&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;dictEntry&lt;/code&gt;  结构定义:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;9&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dictEntry&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;key&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//键&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;unoin&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;val&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// 值&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;unit64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;u64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;        &lt;span class=&#34;kt&#34;&gt;int64_t&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;s64&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;v&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dictEntry&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;next&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dictEntry&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;next&lt;/code&gt; 属性是指向另一个 哈希表节点的指针，该指针可以将多个 hash 键值对连在一起，用来解决哈希冲突的问题。&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;字典&#34;&gt;字典&#xA;&lt;/h3&gt;&lt;p&gt;&lt;code&gt;Redis&lt;/code&gt; 中的字典由&lt;code&gt;dict.h/dict&lt;/code&gt; 结构表示，也就是我们 &lt;code&gt;Redis&lt;/code&gt; 用到的数据结构的最外层了&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;k&#34;&gt;typedef&lt;/span&gt; &lt;span class=&#34;k&#34;&gt;struct&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dict&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;dictType&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//某类型的特定函数&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;void&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;privdata&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//私有数据&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;n&#34;&gt;dictht&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ht&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;];&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;//这里包含了两个Hash 表&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;    &lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;rehashidx&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;;&lt;/span&gt; &lt;span class=&#34;c1&#34;&gt;// rehash索引，用来表示当前rehash的状态&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;del&gt;好累啊，下次再更新&lt;/del&gt;我回来了&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;ht&lt;/code&gt;属性为包含两个项的数组，数组中的每个项都是一个 &lt;code&gt;dictht&lt;/code&gt;  的哈希表，一般情况下 &lt;code&gt;redis&lt;/code&gt; 只会使用第一个hash表，第二个hash表时用来rehash的&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;hashidx&lt;/code&gt;用来记录rehash的状态&#xA;&lt;ul&gt;&#xA;&lt;li&gt;没有进行rehash的时候，值为-1&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;type  属性是一个指向dictType 类型的指针, 这个结构里面包含了一些用于操作特定类型键值对的函数，比如：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;计算哈希值的函数（hashFunction）&lt;/li&gt;&#xA;&lt;li&gt;复制键的函数&lt;/li&gt;&#xA;&lt;li&gt;复制值的函数&lt;/li&gt;&#xA;&lt;li&gt;对比键的函数&lt;/li&gt;&#xA;&lt;li&gt;销毁键的函数&lt;/li&gt;&#xA;&lt;li&gt;销毁值的函数&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;哈希算法&#34;&gt;哈希算法&#xA;&lt;/h3&gt;&lt;p&gt;当添加新键值对进redis 时，redis 首先要根据键计算出哈希值和索引值，再根据索引值将包含键值对的hash表节点（hash桶）放到哈希表数组（哈希桶数组）的指定索引上面&lt;/p&gt;&#xA;&lt;p&gt;计算路径：&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dict&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;type&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hashFunction&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-c&#34; data-lang=&#34;c&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;index&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;hash&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;&amp;amp;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;dict&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;-&amp;gt;&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;ht&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;x&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;].&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;sizemask&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;通过每一种 type 的hash函数计算出hash值，然后和哈希表中的掩码进行按位与运算得到index值&lt;/li&gt;&#xA;&lt;li&gt;使用的算法为 &lt;a class=&#34;link&#34; href=&#34;https://zh.wikipedia.org/wiki/Murmur%e5%93%88%e5%b8%8c&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;MurmurHash2&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;哈希冲突&#34;&gt;哈希冲突&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;redis 使用链地址法 ( separate chaining ) 来解决哈希冲突，每个哈希桶都有一个next指针来构成单链表&lt;/li&gt;&#xA;&lt;li&gt;为了考虑速度，redis 总是将新节点添加到链表头的位置(因为没有指向链表尾的指针，所以如果放在链表尾需要遍历整个链表)&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;rehash&#34;&gt;Rehash&#xA;&lt;/h3&gt;&lt;h4 id=&#34;为什么要rehash&#34;&gt;为什么要rehash？&#xA;&lt;/h4&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;随着操作的不断的执行，哈希表保存的键值对会相应增加或者减少,如果一个索引上链接这N多键值对而其他索引上有没有键值对&lt;del&gt;那和遍历一个链表有什么区别&lt;/del&gt;&lt;/p&gt;&#xA;&lt;p&gt;所以为了让哈希表的负载因子维持在一个合理的范围内，就需要对hash表进行相应的扩容和收缩&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;rehash是指重新计算键的hash值和index值&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;负载因子=ht[0].used /  ht[0].size&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;&lt;h4 id=&#34;rehash-步骤&#34;&gt;rehash 步骤&#xA;&lt;/h4&gt;&lt;ol start=&#34;0&#34;&gt;&#xA;&lt;li&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;redis 没有执行&lt;code&gt;BGSAVE&lt;/code&gt; 或者 &lt;code&gt;BGREWRITEAOF&lt;/code&gt; 命令时，负载因子大于 1 开始扩展&lt;/li&gt;&#xA;&lt;li&gt;执行&lt;code&gt;BGSAVE&lt;/code&gt; 或者 &lt;code&gt;BGEWRITEAOF&lt;/code&gt; 时，负载因子大于 5 开始拓展&lt;/li&gt;&#xA;&lt;li&gt;负载因子小于 0.1 时开始收缩&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;创建适当空间用于 ht[1] ，空间大小取决于是要扩展收缩以及现在ht[0] 中存在的键值对数量 (&lt;code&gt;dict-&amp;gt;ht[0]-&amp;gt;used&lt;/code&gt;)&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;拓展&lt;/strong&gt;: 创建新 hashtable 的大小为 第一个大于等于两倍的现在已存在的键值对数量的2的n次方&lt;/li&gt;&#xA;&lt;li&gt;&lt;del&gt;说起来有点绕，我自己都不知道在说什么&lt;/del&gt;&lt;/li&gt;&#xA;&lt;li&gt;假如现在存了7个键值对，那么就是要扩展到大于2*7=14 个的 hashtable&lt;/li&gt;&#xA;&lt;li&gt;2^0 =1 不够，2^1不够，2^2不够，2^3不够，2^4 够了够了谢谢妈妈妈妈真好！就它了！所以新创建的表大小为16~&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;收缩&lt;/strong&gt;：新hashtable的大小为第一个大于等于现在已存在的键值对数量的2的n次方&lt;/li&gt;&#xA;&lt;li&gt;一样举例，比如现在hashtable 大小为8，但是只存了三个数据，就缩小到4&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;将 ht[0] 上的键值对 rehash 到 ht[1] 上，具体怎么rehash 请查看后面的 &lt;strong&gt;渐进式rehash&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;迁移完成后，释放 ht[0] , 将 ht[1] 设为 ht[0] ， 同时创建新的 ht[1] 准备下一次 rehash&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;h4 id=&#34;渐进式-rehash&#34;&gt;渐进式 rehash&#xA;&lt;/h4&gt;&lt;p&gt;顾名思义，就是慢慢慢慢 rehash， 并不是一次性做完&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&lt;code&gt;rehashidx&lt;/code&gt;  设置为 0 ,表示 rehash 工作正式开始&lt;/li&gt;&#xA;&lt;li&gt;当对某个键做出增删查改的操作时，redis 都会将该键索引上的键值对 rehash 到 ht[1],同时rehashidx 加1&lt;/li&gt;&#xA;&lt;li&gt;当 rehash 全部完成后，rehashidx 重新设置为 -1&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;p&gt;&lt;em&gt;在rehash 过程中，查找会先在 ht[0] 上查找，如果没有则到 ht[1] 上查找；而添加 则只会在 ht[1] 上添加。保证 ht[0] 只增不减&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;go-中的--hash&#34;&gt;Go 中的  Hash&#xA;&lt;/h2&gt;&lt;h3 id=&#34;结构图-1&#34;&gt;结构图&#xA;&lt;/h3&gt;&lt;img src=&#34;https://static.guoxy.top/img/go-map.png&#34; style=&#34;zoom: 50%;&#34; /&gt;&#xA;&lt;h3 id=&#34;hash-表-1&#34;&gt;hash 表&#xA;&lt;/h3&gt;&lt;p&gt;Go 中的 hash 表在 &lt;code&gt;/src/runtime/map.go&lt;/code&gt; 中定义&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;13&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;14&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;15&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hmap&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Note: the format of the hmap is also encoded in cmd/compile/internal/gc/reflect.go.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Make sure this stays in sync with the compiler&amp;#39;s definition.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;count&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;int&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// # live cells == size of map.  Must be first (used by len() builtin)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;         &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// log_2 of # of buckets (can hold up to loadFactor * 2^B items)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;noverflow&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint16&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// approximate number of overflow buckets; see incrnoverflow for details&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;hash0&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint32&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// hash seed&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;buckets&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// array of 2^B Buckets. may be nil if count==0.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;oldbuckets&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;unsafe&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;Pointer&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// previous bucket array of half the size, non-nil only when growing&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;nevacuate&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uintptr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;        &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// progress counter for evacuation (buckets less than this have been evacuated)&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;extra&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;o&#34;&gt;*&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;mapextra&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// optional fields&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;Go 的源码注释一直是很完善的，想必看注释也看得八九不离十了&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;code&gt;count&lt;/code&gt;  属性 就是 &lt;code&gt;len(map)&lt;/code&gt; 调用得到的值，map 中存在的键值对的数量&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;flag &lt;/code&gt;属性暂时还不清楚&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;B&lt;/code&gt; 属性用来标记hash 桶的数量，是2的指数，也就是 B 为3 的时候 hash bucket 的数量为8&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt; noverflow&lt;/code&gt;  属性是 overflow 的 bucket 近似数&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt; hash0&lt;/code&gt;  属性是哈的种子，它能为哈希函数的结果引入随机性，这个值在创建哈希表时确定，并在调用哈希函数时作为参数传入&lt;/li&gt;&#xA;&lt;li&gt;&lt;code&gt;oldbuckets&lt;/code&gt; 是哈希在扩容时用于保存之前 &lt;code&gt;buckets&lt;/code&gt; 的字段，它的大小是当前 &lt;code&gt;buckets&lt;/code&gt; 的一半&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;hash-桶&#34;&gt;hash 桶&#xA;&lt;/h3&gt;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt; 1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 7&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 8&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt; 9&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;10&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;11&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;12&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;c1&#34;&gt;// A bucket for a Go map.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bmap&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// tophash generally contains the top byte of the hash value&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// for each key in this bucket. If tophash[0] &amp;lt; minTopHash,&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// tophash[0] is a bucket evacuation state instead.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;tophash&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bucketCnt&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Followed by bucketCnt keys and then bucketCnt elems.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// NOTE: packing all the keys together and then all the elems together makes the&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// code a bit more complicated than alternating key/elem/key/elem/... but it allows&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// us to eliminate padding which would be needed for, e.g., map[int64]int8.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;&#x9;&lt;/span&gt;&lt;span class=&#34;c1&#34;&gt;// Followed by an overflow  pointer.&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;看似这个结构里只有一个属性，其实在编译期间会对 该结构进行重建，重建得到的 struct 如下&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;4&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;5&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;6&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;7&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-go&#34; data-lang=&#34;go&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;kd&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;bmap&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kd&#34;&gt;struct&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;topbits&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;  &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uint8&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;keys&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;     &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;keytype&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;values&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;   &lt;/span&gt;&lt;span class=&#34;p&#34;&gt;[&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;8&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;]&lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;valuetype&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;pad&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;      &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uintptr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;w&#34;&gt;    &lt;/span&gt;&lt;span class=&#34;nx&#34;&gt;overflow&lt;/span&gt;&lt;span class=&#34;w&#34;&gt; &lt;/span&gt;&lt;span class=&#34;kt&#34;&gt;uintptr&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;p&#34;&gt;}&lt;/span&gt;&lt;span class=&#34;w&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;上面猛男色对应的就是 &lt;code&gt;topbits&lt;/code&gt; / &lt;code&gt;tophash&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;青色对应的是 &lt;code&gt;keys&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;黄色对应的是 &lt;code&gt;values&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;基佬色：每个桶只能装8个键值对，当溢出时，就需要链接 一个溢出桶，你懂的&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;key-的寻找过程&#34;&gt;Key 的寻找过程&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;当一个 key 甩过来让你找，当然是用 hash 函数计算 hash 值辣，那么就能得到一个 64 位的 hash 值（32 位CPU得到的是32位，是时候退出群聊了）&lt;/li&gt;&#xA;&lt;li&gt;假设 &lt;code&gt;hmap.B&lt;/code&gt;  为 5， 那么一共就有 2^5 也就是 32 个 hash 桶&lt;/li&gt;&#xA;&lt;li&gt;经过计算后得到下面的hash值&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt; 10010111  000011110110110010001111001010100010010110010101010  01010&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;我们对后 &lt;code&gt;B&lt;/code&gt;  位 ( 这里是5 )进行对 &lt;code&gt;B&lt;/code&gt;  取余操作 ( 实现时是用按位操作，取余开销太大，这里说取余是为了方便理解 )，得到值为 10，所以要找的值在10 号桶里&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;进入 10 号桶，再取 hash 值的高 8 位，就是前面 &lt;code&gt;bmap&lt;/code&gt; 中定义的 &lt;code&gt;tophash&lt;/code&gt;了，然后对比，桶里面 &lt;code&gt;tophash&lt;/code&gt; 在哪个位置那么 键 和 值 就在哪个位置&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;如果 8 个&lt;code&gt;tophash&lt;/code&gt; 都没有的话，进入溢出桶继续寻找，如果走遍溢出桶都没有，那就是真没有&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;em&gt;word is cheap show me the picture&lt;/em&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;img src=&#34;https://static.guoxy.top/img/goMapFindKey.png&#34; style=&#34;zoom: 33%;&#34; /&gt;&#xA;&lt;h3 id=&#34;rehash-1&#34;&gt;rehash&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;同样这里有一个装载因子的概念，Go源码给的定义是这样的：&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-gdscript3&#34; data-lang=&#34;gdscript3&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;loadFactor&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;count&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;/&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;mi&#34;&gt;2&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;^&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;B&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;扩容条件：&#xA;&lt;ul&gt;&#xA;&lt;li&gt;装载因子超过阈值，源码里定义的阈值是 6.5&lt;/li&gt;&#xA;&lt;li&gt;overflow 的 bucket 数量过多：当 B 小于 15，也就是 bucket 总数 2^B 小于 2^15 时，如果 overflow 的 bucket 数量超过 2^B；当 B &amp;gt;= 15，也就是 bucket 总数 2^B 大于等于 2^15，如果 overflow 的 bucket 数量超过 2^15&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h4 id=&#34;增量扩容&#34;&gt;增量扩容&#xA;&lt;/h4&gt;&lt;p&gt;当满足第一个扩容条件时触发增量扩容&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;创建一组新桶，桶的数量是旧桶数量的两倍&lt;/li&gt;&#xA;&lt;li&gt;将原来的桶 设置到 &lt;code&gt;oldbuckets&lt;/code&gt; 上，再将新桶设置到 &lt;code&gt;buckets&lt;/code&gt; 上，同理 &lt;code&gt;overflow&lt;/code&gt; 也设置到 &lt;code&gt;oldoverflow&lt;/code&gt; 上&lt;/li&gt;&#xA;&lt;li&gt;渐进式 hash：go 只在 插入、更新、删除 操作上会发生搬迁工作，而且每次最多搬迁两个 &lt;code&gt;bucket&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;搬迁时 怎么确定 落入哪个新桶？&lt;/li&gt;&#xA;&lt;li&gt;由之前的知识我们知道落入哪个桶时由 hash 值的后 B 位决定的&lt;/li&gt;&#xA;&lt;li&gt;比如 扩容前B是 ⑤，所以由后 5 位 决定，现在扩容成了 ⑥ ， 所以就在加一位，由 6 位决定&lt;/li&gt;&#xA;&lt;li&gt;这样能保证 旧桶的能够落到两个新桶内&lt;/li&gt;&#xA;&lt;li&gt;当搬迁完毕时 &lt;code&gt;oldbuckets&lt;/code&gt; 和 &lt;code&gt;oldoverflow&lt;/code&gt; 设为 &lt;code&gt;nil&lt;/code&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;em&gt;所以当每次进行插入，更新，删除的操作时，会判断 &lt;code&gt;oldbuckets&lt;/code&gt; 状态 来确定是否在扩容中&lt;/em&gt;&lt;/p&gt;&#xA;&lt;h4 id=&#34;等量扩容&#34;&gt;等量扩容&#xA;&lt;/h4&gt;&lt;p&gt;当满足第二个条件时进行等量扩容&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;可能是由于大量插入再大量删除键值对造成的，会导致键值对在桶（以及 &lt;code&gt;overflow&lt;/code&gt; ）中过于分散，就像一座城由很多房子，很多是空的，只有几栋房子有人家，我们就很难找到他们，那只要我们将他们集中在某个小区中，我们就能够快速的找到他们 ~&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;当扩容完毕后，所有的键值对都集中到了相对集中的 &lt;code&gt;bucket&lt;/code&gt; 上，&lt;code&gt;overflow&lt;/code&gt; 上的键值对就拜拜辣&lt;/p&gt;&#xA;&lt;h2 id=&#34;总结&#34;&gt;总结&#xA;&lt;/h2&gt;&lt;h3 id=&#34;相同点&#34;&gt;相同点&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;hashtable&lt;/code&gt; -&amp;gt; &lt;code&gt;hashbucket&lt;/code&gt; -&amp;gt; &lt;code&gt;key/value&lt;/code&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;都使用拉链法来解决 hash 冲突，但是也有不同的是 &lt;code&gt;Redis&lt;/code&gt; 是链接 键值对，&lt;code&gt;Go&lt;/code&gt; 链接溢出桶&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;rehash 时都采用渐进式 rehash&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;不同点&#34;&gt;不同点&#xA;&lt;/h3&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;&lt;code&gt;Redis&lt;/code&gt; 一个桶只能存一个键值对； &lt;code&gt;Go&lt;/code&gt; 一个桶存可以存 8 个键值对&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;确定位置时 &lt;code&gt;Redis&lt;/code&gt; 使用的是 hash 值 和 表掩码为与 得到 索引值 确定位置； &lt;code&gt;Go&lt;/code&gt; 用 hash 值得 高8位和低 B 位确定位置&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;参考&#34;&gt;参考&#xA;&lt;/h2&gt;&#xA;    &lt;blockquote&gt;&#xA;        &lt;p&gt;&lt;em&gt;《Redis 设计与实现》&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;a class=&#34;link&#34; href=&#34;https://github.com/cch123/golang-notes/blob/master/channel.md&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;cch123/golang-notes&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;&lt;a class=&#34;link&#34; href=&#34;https://draveness.me/golang/docs/part2-foundation/ch03-datastructure/golang-hashmap/&#34;  target=&#34;_blank&#34; rel=&#34;noopener&#34;&#xA;    &gt;Go 设计与实现&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;&#xA;&#xA;    &lt;/blockquote&gt;&#xA;</description>
        </item></channel>
</rss>
