前言
说实话,如果不是因为金三银四,我也不会抽时间,翻开sync.map的源代码来温故知新。每次看sync.map的源代码,每次都是当天能记住其中的原理,隔了一段时间再看,脑海里会多了好多❓。干脆,趁这次有时间,有刚需,就整理一下自己对sync.map的理解。
介绍
sync.map结构体包含了最主要的两个字段---read和dirty。故名思义,会让人联想到读写分离的概念思维。如果今天,还是用这种思维去理解sync.map,我列出了几个问题,如下:
- amended字段是什么含义❓
- expunged字段是什么含义❓
- 为什么在delete一个在read的key,是置nil,而不是删除❓
- read的数据是何时同步到dirty中的❓
- dirty的数据是何时同步到read中的❓ 我相信如果用读写分离的角度去解释上述的几个问题,很难自圆其说。如果换成缓存和数据库呢❓❓❓
类比思维
如果把read看作是缓存,那么dirty就非数据库不可了。
问题3
有了缓存和数据库,说实话,问题3就很好理解了。我们知道,如果在缓存中删除了一个key,当我们日后重复访问这个key的时候,会发生什么问题?是不是我们常常挂在嘴边的缓存穿透呢?如何解决缓存穿透?通常的做法,是不是赋一个默认值?巧了,sync.Map是不是就赋值了一个nil的默认值。
问题2
接着我们来思考问题2。我们先来讲一下expaunged的含义:表示这个key,只存在于read。如问题3所讲的,删除一个read中的key,value直接置为nil,那么,是什么时候将nil改为expaunged?我们动动双手,翻开源代码,会发现在Store方法中。如果换成更通俗的语言来讲,就是在问题4中,当read的数据同步到dirty的时候,会将nil的改成expauned。
问题4
紧接着我们来思考问题4。我们此处将read替换成缓存,dirty替换成数据库。缓存的数据是何时同步到数据库中?或者说缓存的数据为什么要同步到数据库中?是不是有种回写的意思?何时?当我们往sync.map插入一个既不在read,也不在dirty中的key,就会触发一次回写,顺便将read中的nil的改成expunged,正好和expunged含义所吻合--只存在于read。
问题5
古有缓存的数据同步到数据库中,现有数据库的数据同步到缓存。我们何时会从数据库的数据写到缓存呢?是不是缓存没有数据,就会将数据库的数据同步到缓存呢。用我们日常的开发思维套用在问题5也能很好地解释的通。问题又来了,何时发生?动动双手,翻开源代码,没错,在Load中,当我们的缓存未命中次数等于数据库的数据长度,怎么样,能理解了么?换成一句人话,就是缓存中没有数据,那干脆从数据库中取一份全量数据吧。
问题1
最后一个问题,amended字段含义正好和expunged相反,表示某个key,只存在于dirty中。表示这个数据只在数据库,缓存中没有哦。
结尾
有时候,当我们站在某个角度思考一个问题时,解释不通的时候,请换一个角度,说不定会有意想不到的收获。