zoukankan      html  css  js  c++  java
  • 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。

     

  • 相关阅读:
    ab参数详解 – 压力测试
    configure/make/make install的作用
    LNMP第二部分nginx、php配置
    centos 6.9安装mysql
    HDFS Java API的使用举例
    配置SSH无秘钥登录
    一篇文章学懂Shell脚本
    自己实现一个简单的网购秒杀系统
    hadoop伪分布式环境搭建
    vmware虚拟机的克隆
  • 原文地址:https://www.cnblogs.com/DillGao/p/11118842.html
Copyright © 2011-2022 走看看