struct
1 | // Map is like a Go map[interface{}]interface{} but is safe for concurrent use |
1 | type Map struct { |
map
Load()
1 |
|
note
- 先从read查,查到就直接返回。查不到并且
read.amended=true(dirty!=read)
再去dirty中查,查dirty要加互斥锁。 - 这里用到了两次查询,参考单例的设计。
- read是
atomic.value
类型的,atomic.value的Load/Store
是线程安全的,所以不用加锁,读性能比较好。但是其实也用到了cas
,所以也用到了lock指令,不是完全无锁定的。
demo
1 | package main |
Store()
1 |
|
note
- 任何值可以赋值给空接口的值,空接口的值也可以赋值给任何值
- 第一次新增和misscount达到限制都会刷新dirty(吧read赋值给dirty,如果read为空,这一步就提前ret)
- store包含了更新和新增
- 这里加锁是给m.dirty加锁,加锁是内核的调度器执行的主要用于大的复合对象/临界区,原子操作是硬件指令主要针对单个值
- (新增元素或者刷新dirty的时候)tryExpungeLocked将nil的标记为已删除expunged,新增entry的时候read如果能读到,unexpungeLocked对于expunged又改为nil并更新dirty
demo
missLocked
1 | func (m *Map) missLocked() { |
LoadOrStore
1 |
|
note
load和store的结合体,不赘述
Delete
1 | // Delete deletes the value for a key. |
LoadAndDelete
1 | // LoadAndDelete deletes the value for a key, returning the previous value if any. |
note
- 如果read中找到了,直接在read标记删除,否则才去找dirty
- read的删除,对于nil/expunged直接ret,不然标记为nil
- dirty的删除,才是真的删除
- 删除dirty也会使misscount+1
Range
1 | // Range calls f sequentially for each key and value present in the map. |
dirtyLocked
1 | func (m *Map) dirtyLocked() { |
entry
1 |
|
tryStore
1 | // tryStore stores a value if the entry has not been expunged. |
unexpungeLocked
1 | // unexpungeLocked ensures that the entry is not marked as expunged. |
storeLocked
1 | // storeLocked unconditionally stores a value to the entry. |
tryLoadOrStore
1 | // tryLoadOrStore atomically loads or stores a value if the entry is not |
delete
1 | func (e *entry) delete() (value interface{}, ok bool) { |
tryExpungeLocked
1 | func (e *entry) tryExpungeLocked() (isExpunged bool) { |
总结
- misscount达到阈值,将dirty刷回read,set dirty=nil
- 新增元素的时候(区别与修改),如果amend=false,则将read刷回dirty
reference
[1]https://colobu.com/2017/07/11/dive-into-sync-Map/
[2]https://draveness.me/golang/docs/part2-foundation/ch03-datastructure/golang-hashmap/