热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

go语言的map结构delete方法源码解读

<pre


func mapdelete(t *maptype, h *hmap, key unsafe.Pointer) {
if raceenabled && h != nil {
callerpc := getcallerpc()
pc := funcPC(mapdelete)
racewritepc(unsafe.Pointer(h), callerpc, pc)
raceReadObjectPC(t.key, key, callerpc, pc)
}
if msanenabled && h != nil {
msanread(key, t.key.size)
}
if h == nil || h.count == 0 {
if t.hashMightPanic() {
t.key.alg.hash(key, 0) // see issue 23734
}
return
}
if h.flags&hashWriting != 0 {
throw("concurrent map writes")
}
//go语言可以选择hash和equals的不同实现
alg := t.key.alg
//根据key获取hash值
hash := alg.hash(key, uintptr(h.hash0))
// Set hashWriting after calling alg.hash, since alg.hash may panic,
// in which case we have not actually done a write (delete).
//走到这一步说明我们对key计算hash值的时候没有发生panic,所以后边我们可以标识我们正在对
//此map进行操作
h.flags ^= hashWriting
//bucketMask(h.B)方法是生成B个1的二进制方法,比如B为5的话,则bucketMask(h.B)返回11111
然后与hash值进行与计算会获取到hash值的低B位的十进制数,也就是我们key在bucket数组里的角标,
//这个方法跟java语言里hashmap计算key位于哪个桶的方法是一样的,都是采用与运算代替取模计算(取模耗费性能),
//只不过java写法是hash&(B-1),bucketMask(h.B)方法的具体实现就是B-1
bucket := hash & bucketMask(h.B)
//go语言的map结构扩容时不会立即迁移所有的数据,跟redis一样会慢慢迁移,用到哪个bucket就会迁移哪个,
//下边代码就是判断此bucket是否在迁移,是的话会先迁移,然后再进行后续操作。
if h.growing() {
growWork(t, h, bucket)
}
//使用指针计算类似于start index*bucketLength,也即获取执行角标位置的链表的头节点指针
b := (*bmap)(add(h.buckets, bucket*uintptr(t.bucketsize)))
//这个赋值是为下边的向前遍历链表赋值emptyRest做准备
bOrig := b
//计算hash值得高8位,tophash和key数组以及val数据的关系如下所示,因此我们只需要比对tophash
//就可以立即定位到key和val的位置
|tophash0 |tophash1 |tophash2 |tophash3 |tophash4 |tophash5 |tophash6 |tophash7 |
|k0 |k1 |k2 |k3 |k4 |k5 |k6 | k7 |
|val0 |val1 |val2 |val3 |val4 |val5 |val6 | val7 |
top := tophash(hash)
search:
//外层循环,依次循环bucket和溢出bucket
for ; b != nil; b = b.overflow(t) {
//内层循环,从角标0开始依次查找tophash是否在此bucket里
for i := uintptr(0); i //首先处理不存在时的逻辑
if b.tophash[i] != top {
//如果当前tophash值是emptyRest ,
//则代表i之后的所有当前bucket里tophash都是空且此bucket的溢出bucket里的tophash也是空
//(就是i之后的位置压根就没有被使用,类似slice的cap属性,redis里sds的free属性),
//因此后边就不用找了,直接退出循环
if b.tophash[i] == emptyRest {
break search
}
//否则继续查找
continue
}
//这里代表当前bucket里有和key的tophash值相同的tophash值,
//获取key的指针地址,首先定位bmap地址 偏移量(会偏移到k0初始地址) i*t.keysize
k := add(unsafe.Pointer(b), dataOffset i*uintptr(t.keysize))
k2 := k
//此处判断key是否是指针类型,是:获取到key值
if t.indirectkey() {
k2 = *((*unsafe.Pointer)(k2))
}
//使用之前选定的equals方法比较
if !alg.equal(key, k2) {
continue
}
// Only clear key if there are pointers in it.
//key是指针类型,只把指针置为nil,数据等待gc去处理
if t.indirectkey() {
*(*unsafe.Pointer)(k) = nil
} else if t.key.kind&kindNoPointers == 0 {
//key是非指针类型,清除数据
memclrHasPointers(k, t.key.size)
}
v := add(unsafe.Pointer(b), dataOffset bucketCnt*uintptr(t.keysize) i*uintptr(t.valuesize))
if t.indirectvalue() {
*(*unsafe.Pointer)(v) = nil
} else if t.elem.kind&kindNoPointers == 0 {
memclrHasPointers(v, t.elem.size)
} else {
memclrNoHeapPointers(v, t.elem.size)
}
//此时只可以确定当前位置为空了,
b.tophash[i] = emptyOne
// If the bucket now ends in a bunch of emptyOne states,
// change those to emptyRest states.
//如果当前的bucket以多个emptyOne 状态结尾,则把这些emptyOne 都改为emptyRest 状态
// It would be nice to make this a separate function, but
// for loops are not currently inlineable.
//如果i是7的话(就是在当前bucket的tophash的最后一个位置)
if i == bucketCnt-1 {
//如果当前bucket有溢出bucket且溢出bucket的tophash的0下标不是emptyRest,则不进行处理,直接结束外层循环
if b.overflow(t) != nil && b.overflow(t).tophash[0] != emptyRest {
goto notLast
}
} else {
//
if b.tophash[i 1] != emptyRest {
goto notLast
}
}
//这里就是从当前i开始往前把连续的emptyOne都置为emptyRest
for {
b.tophash[i] = emptyRest
if i == 0 {
if b == bOrig {
break // beginning of initial bucket, we're done.
}
// Find previous bucket, continue at its last entry.
c := b
for b = bOrig; b.overflow(t) != c; b = b.overflow(t) {
}
i = bucketCnt - 1
} else {
i--
}
//一旦不是,立即停止循环
if b.tophash[i] != emptyOne {
break
}
}
notLast:
//为hash表的count属性赋值
h.count--
break search
}
}
if h.flags&hashWriting == 0 {
throw("concurrent map writes")
}
h.flags &^= hashWriting
}

 


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了Redis的基础数据结构string的应用场景,并以面试的形式进行问答讲解,帮助读者更好地理解和应用Redis。同时,描述了一位面试者的心理状态和面试官的行为。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 1,关于死锁的理解死锁,我们可以简单的理解为是两个线程同时使用同一资源,两个线程又得不到相应的资源而造成永无相互等待的情况。 2,模拟死锁背景介绍:我们创建一个朋友 ... [详细]
  • Python正则表达式学习记录及常用方法
    本文记录了学习Python正则表达式的过程,介绍了re模块的常用方法re.search,并解释了rawstring的作用。正则表达式是一种方便检查字符串匹配模式的工具,通过本文的学习可以掌握Python中使用正则表达式的基本方法。 ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 目录实现效果:实现环境实现方法一:基本思路主要代码JavaScript代码总结方法二主要代码总结方法三基本思路主要代码JavaScriptHTML总结实 ... [详细]
  • 本文介绍了如何在给定的有序字符序列中插入新字符,并保持序列的有序性。通过示例代码演示了插入过程,以及插入后的字符序列。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • 本文探讨了C语言中指针的应用与价值,指针在C语言中具有灵活性和可变性,通过指针可以操作系统内存和控制外部I/O端口。文章介绍了指针变量和指针的指向变量的含义和用法,以及判断变量数据类型和指向变量或成员变量的类型的方法。还讨论了指针访问数组元素和下标法数组元素的等价关系,以及指针作为函数参数可以改变主调函数变量的值的特点。此外,文章还提到了指针在动态存储分配、链表创建和相关操作中的应用,以及类成员指针与外部变量的区分方法。通过本文的阐述,读者可以更好地理解和应用C语言中的指针。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • [大整数乘法] java代码实现
    本文介绍了使用java代码实现大整数乘法的过程,同时也涉及到大整数加法和大整数减法的计算方法。通过分治算法来提高计算效率,并对算法的时间复杂度进行了研究。详细代码实现请参考文章链接。 ... [详细]
  • 开发笔记:Java是如何读取和写入浏览器Cookies的
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了Java是如何读取和写入浏览器Cookies的相关的知识,希望对你有一定的参考价值。首先我 ... [详细]
author-avatar
杜娟小乖_748
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有