go语言map用法 go语言map遍历

Go语言——sync.Map详解【go语言map用法 go语言map遍历】 sync.Map是1.9才推荐的并发安全的map , 除了互斥量以外,还运用了原子操作,所以在这之前 , 有必要了解下 Go语言——原子操作
go1.10\src\sync\map.go
entry分为三种情况:
从read中读取key,如果key存在就tryStore 。
注意这里开始需要加锁,因为需要操作dirty 。
条目在read中,首先取消标记 , 然后将条目保存到dirty里 。(因为标记的数据不在dirty里)
最后原子保存value到条目里面,这里注意read和dirty都有条目 。
总结一下Store:
这里可以看到dirty保存了数据的修改,除非可以直接原子更新read,继续保持read clean 。
有了之前的经验 , 可以猜测下load流程:
与猜测的 区别 :
由于数据保存两份,所以删除考虑:
先看第二种情况 。加锁直接删除dirty数据 。思考下貌似没什么问题,本身就是脏数据 。
第一种和第三种情况唯一的区别就是条目是否被标记 。标记代表删除,所以直接返回 。否则CAS操作置为nil 。这里总感觉少点什么,因为条目其实还是存在的,虽然指针nil 。
看了一圈貌似没找到标记的逻辑,因为删除只是将他变成nil 。
之前以为这个逻辑就是简单的将为标记的条目拷贝给dirty,现在看来大有文章 。
p == nil , 说明条目已经被delete了 , CAS将他置为标记删除 。然后这个条目就不会保存在dirty里面 。
这里其实就跟miss逻辑串起来了,因为miss达到阈值之后,dirty会全量变成read,也就是说标记删除在这一步最终删除 。这个还是很巧妙的 。
真正的删除逻辑:
很绕 。。。。
Go语言使用 map 时尽量不要在 big map 中保存指针 不知道你有没有听过这么一句:在使用 map 时尽量不要在 big map 中保存指针 。好吧go语言map用法,你现在已经听过了:)为什么呢?原因在于 Go 语言go语言map用法的垃圾回收器会扫描标记 map 中的所有元素go语言map用法,GC 开销相当大,直接GG 。
这两天在《Mastering Go》中看到 GC 这一章节里面对比 map 和 slice 在垃圾回收中的效率对比,书中只给出结论没有说明理由 , 这go语言map用法我是不能忍的,于是有了这篇学习笔记 。扯那么多,Show Your Code
这是一个简单的测试程序,保存字符串的 map 和 保存整形的 map GC 的效率相差几十倍,是不是有同学会说明明保存的是 string 哪有指针?这个要说到 Go 语言中 string 的底层实现了,源码在 src/runtime/string.go里 , 可以看到 string 其实包含一个指向数据的指针和一个长度字段 。注意这里的是否包含指针 , 包括底层的实现 。
Go 语言的 GC 会递归遍历并标记所有可触达的对象 , 标记完成之后将所有没有引用的对象进行清理 。扫描到指针就会往下接着寻找,一直到结束 。
Go 语言中 map 是基于 数组和链表 的数据结构实现的 , 通过 优化的拉链法 解决哈希冲突,每个 bucket 可以保存8对键值,在8个键值对数据后面有一个 overflow 指针 , 因为桶中最多只能装8个键值对,如果有多余的键值对落到了当前桶,那么就需要再构建一个桶(称为溢出桶),通过 overflow 指针链接起来 。
因为 overflow 指针的缘故,所以无论 map 保存的是什么,GC 的时候就会把所有的 bmap 扫描一遍,带来巨大的 GC 开销 。官方 issues 就有关于这个问题的讨论 ,  runtime: Large maps cause significant GC pauses #9477
无脑机翻如下:
如果我们有一个map [k] v,其中k和v都不包含指针,并且我们想提高扫描性能,则可以执行以下操作 。

推荐阅读