golang 标准库 sync.Map 中 nil 和 expunge 区别
本文不是 sync.Map 源码详细解读,而是聚焦 entry 的不同状态,特别是 nil 状态和 expunge 状态的区分。
entry 是 sync.Map 存放值的结构体,其值有三种,分别为 value(真正的值)、nil、expunge(任意的指针,标记作用)。如果将其视为一种状态机的话,本文将其三种状态分别称之为value、nil、expunge。
简要概括:
value 状态:entry 里面存放的是真正的值。此时 entry 对应的 key,有三种情况,key 只在 read 中均存在;key 只在 dirty 中存在;在 read 和 dirty 中均存在。
nil 状态:read 中的 key 被删除的时候将其对应的 value(即 entry) p 值设置为 nil。此时 key 只存在 read 中 (ditry 为 nil);在 read 和 dirty 中均存在。
expunge 状态: 此时 key 只存在 read 中而在 dirty 中不存在。
将 sync.Map 抽象为 存、取、删除 三种操作。在这三种操作中来看 entry 状态的改变。
1、存:对于初始状态的 sync.Map, 一个新键值对 k: A v: A, 首先存放在 dirty 中,此时 entry 为 value 状态,key 只存在 dirty 中。
2、取:首先 read 中不存在,从 dirty 中取值。数次从 read 中取不中,将 dirty 提升为 read, dirty 被清空。entry 仍为 value 状态,对应的 key 存在于 read 中。
3、存:另一键值对k:B v:B,存入时,发生 read 向 dirty 拷贝,同时 read 的 amended 标记为 true。此时 key A 存在于 read 和 dirty 中,entry 为 value 状态。
4、删除:删除 key A,A 的 entry 中 p 值被设置为 nil。此时 key A 存在于 read 和 dirty 中,entry 为 nil 状态。
5、存:另一键值对k:C v:C。
6、取:多次读取 key C,触发 dirty 提升为 read,dirty 被清空。此时 key A 只存在于 read 中, entry 为 nil 状态。
7、存:另一键值对 k:D v:D, 存入时,发生 read 向 dirty 拷贝,key A 的 entry 由 nil 状态转变为 expunge 状态,key A 只存在于 read 中。
8、取:多次读取 key D,触发 dirty 提升为 read, dirty 被清空,此时 key A 被完全删除。
为什么会用 nil 和 expunge 两种状态来标记一个值的删除?
首先明确,什么时候 expunge 出现。当key A 的值在 read 中为 nil,随后由其他操作触发 read 向 dirty 复制,nil 被转变为 expunge。此时 dirty 不为空,且 key A 在 dirty 中不存在。如果对 key A 重新赋值,修改 read 后,需要同步修改 dirty ,为了保障当 dirty 提升为 read 时,包含所有的值。
再来看 nil 的清空,当 key A 的值为 nil 状态的时候,key A 存在于 read 和 dirty 中或仅存在于 read 中(dirty 为空),因为 read 和 dirty 中相同的 key 指向同一值的指针,因此在这两种情况下,对 key A 重新赋值,均无需考虑 dirty。
golang 标准库 sync.Map 中 nil 和 expunge 区别的更多相关文章
- golang 标准库间依赖的可视化展示
简介 国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内 ...
- Golang 标准库log的实现
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1406905 前 ...
- golang标准库 context的使用
本文索引 问题引入 context包简介 示例 问题引入 goroutine为我们提供了轻量级的并发实现,作为golang最大的亮点之一更是备受推崇. goroutine的简单固然有利于我们的开发,但 ...
- Go 标准库 —— sync.Mutex 互斥锁
Mutex 是一个互斥锁,可以创建为其他结构体的字段:零值为解锁状态.Mutex 类型的锁和线程无关,可以由不同的线程加锁和解锁. 方法 func (*Mutex) Lock func (m *Mut ...
- Golang 标准库提供的Log(一)
原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://gotaly.blog.51cto.com/8861157/1405754 G ...
- golang标准库分析之net/rpc
net/rpc是golang提供的一个实现rpc的标准库.
- golang 标准库
前言 不做文字搬运工,多做思路整理 就是为了能速览标准库,只整理我自己看过的...... 最好能看看英文的 标准库 fmt strconv string 跳转 golang知识库总结
- STL标准库-容器-map和multimap
技术在于交流.沟通,本文为博主原创文章转载请注明出处并保持作品的完整性 map与multimap为关联容器,结构如下 map底层实现依然是rb_tree 他的data可以改,但是key不能改,因此ma ...
- C 标准库IO缓冲区和内核缓冲区的区别
1.C标准库的I/O缓冲区 UNIX的传统 是Everything is a file,键盘.显示器.串口.磁盘等设备在/dev 目录下都有一个特殊的设备文件与之对应,这些设备文件也 ...
随机推荐
- 转载:利用php数组函数进行函数式编程
因为一个BUG, 我在一个摇摇欲坠,几乎碰一下就会散架的项目中某一个角落中发现下面这样一段代码 这段程序与那个BUG有密切的关系. 我来回反复的捉摸这段代码, 发现这段代码实现了两个功能 第一个是在一 ...
- docker命令(随时补充)
导入导出容器:https://blog.csdn.net/LEoe_/article/details/78685156 拷贝文件到容器内:docker cp 本地路径 容器长ID:容器路径
- mongodb数据库的改操作
原来字段: { "_id" : ObjectId("5df0a28e406405edeac5001f"), "username" : &qu ...
- Eclipse中对一个项目进行复制粘贴为一个新项目
1:对目标项目执行右键,选择“Copy”,然后在空白处右键,选择“Paste”结果如下图: 2:右键新项目,点击Properties, 3:打开Navigator视图 4:打开.settings文件夹 ...
- 【leetcode】1191. K-Concatenation Maximum Sum
题目如下: Given an integer array arr and an integer k, modify the array by repeating it k times. For exa ...
- 阿里云服务器 CentOS 7.5 64位 docker安装redis集群
网上有很多教程可以参考,但是遇到坑了...... 最后参考这个教程成功了.https://www.cnblogs.com/hbbbs/articles/10028771.html 安装docker 参 ...
- css-select的三角在不同浏览器的样式是不一样的,所以我们这样解决???
select{ width:57px; height:23px; border:1px solid #e9e9e9; outline: none; appearance: none; -moz-app ...
- $.param()序列化对象
1.$.param(): param() 方法创建数组或对象的序列化表示形式. 序列化的值可在生成 AJAX 请求时用于 URL 查询字符串中. 第一行是原始数据,第二行是序列化后的.$.param( ...
- 镜像源操作-ananconda-docker
CentOS mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.repo.backup CentOS 6 wget - ...
- SQL基础测试
SQL 测验 结果:20/20 您的回答: 1.SQL 指的是? 您的回答:Structured Query Language 2.哪个 SQL 语句用于从数据库中提取数据? 您的回答:SELECT ...