golang sync.Map

sync.Map的使用

正常情况下,在函数内记录哈希关系我们会使用到map,简单高效;

但在使用全局hash结构时,高并发场景下,会有map读写panic的问题;

解决的方法常有:

给map加锁(互斥锁,读写锁)
使用golang  1.9之后的sync.Map
使用外部开源安全缓存,比如cache等

本次主要介绍sync.Map的一些用法

var m sync.Map
// 1. 写入
m.Store("testmap", 888)

// 2. 读取
age, ok := m.Load("testmap")
if ok{
	fmt.Println(age.(int))
}

// 3. 遍历
m.Range(func(key, value interface{}) bool {
    name := key.(string)
    age := value.(int)
    fmt.Println(name, age)
    return true
})

// 4. 删除
m.Delete("testmap")
age, ok := m.Load("testmap")
fmt.Println(age, ok)

// 5. 读取或写入
m.LoadOrStore("testmap", 168)
age, _ = m.Load("testmap")
fmt.Println(age)

sync.map原理分析

主要是以下几个函数

func (m *Map) Store(key, value interface{}) {
	read, _ := m.read.Load().(readOnly)
	//如果read中存在,并且状态不是删除,则直接进行原子性操作置换新数据后返回
	//此处应该是更新的情况直接更新地址指向的内容
	if e, ok := read.m[key]; ok && e.tryStore(&value) {
		return
	}
	
	
	m.mu.Lock()
	read, _ = m.read.Load().(readOnly)
	//加锁后,再次进行检查
	if e, ok := read.m[key]; ok {
	//检查是否已经有删除标记
		if e.unexpungeLocked() {
			// The entry was previously expunged, which implies that there is a
			// non-nil dirty map and this entry is not in it.
			m.dirty[key] = e
		}
		e.storeLocked(&value)//更新二级缓存
	} else if e, ok := m.dirty[key]; ok {
		e.storeLocked(&value)//更新二级缓存
	} else {
		//没有未更新的情况,同步
		if !read.amended {
			// We're adding the first new key to the dirty map.
			// Make sure it is allocated and mark the read-only map as incomplete.
			m.dirtyLocked()	//更新dirty,从一级缓存到二级缓存,read到dirty
			m.read.Store(readOnly{m: read.m, amended: true})//重新标记有未更新的
		}
		m.dirty[key] = newEntry(value)//设置dirty
	}
	m.mu.Unlock()
}



func (m *Map) Load(key interface{}) (value interface{}, ok bool) {
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	if !ok && read.amended {
		m.mu.Lock()
		// Avoid reporting a spurious miss if m.dirty got promoted while we were
		// blocked on m.mu. (If further loads of the same key will not miss, it's
		// not worth copying the dirty map for this key.)
		//(复看是因为存在二级缓存向一级缓存同步数据的情况),有就返回对应value
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]
		if !ok && read.amended {
			e, ok = m.dirty[key]
			// Regardless of whether the entry was present, record a miss: this key
			// will take the slow path until the dirty map is promoted to the read
			// map.
			m.missLocked()//这里会会进行读击穿次数检查,将dirty置换给read,并且dirty和miss会置空,miss下次会重新计数
		}
		m.mu.Unlock()
	}
	if !ok {
		return nil, false
	}
	return e.load()
}

func (m *Map) LoadAndDelete(key interface{}) (value interface{}, loaded bool) {
	read, _ := m.read.Load().(readOnly)
	e, ok := read.m[key]
	if !ok && read.amended {
		m.mu.Lock()
		read, _ = m.read.Load().(readOnly)
		e, ok = read.m[key]//复检
		if !ok && read.amended {//有同步情况则直接删除dirty中
			e, ok = m.dirty[key]
			delete(m.dirty, key)
			// Regardless of whether the entry was present, record a miss: this key
			// will take the slow path until the dirty map is promoted to the read
			// map.
			m.missLocked()//修改也会对miss新增
		}
		m.mu.Unlock()
	}
	if ok {//不存在有更新的情况直接删除read中的就行
		return e.delete()
	}
	return nil, false
}

// Delete deletes the value for a key.
func (m *Map) Delete(key interface{}) {
	m.LoadAndDelete(key)
}

func (e *entry) delete() (value interface{}, ok bool) {
	for {
		p := atomic.LoadPointer(&e.p)
		if p == nil || p == expunged {
			return nil, false
		}
		if atomic.CompareAndSwapPointer(&e.p, p, nil) {
			return *(*interface{})(p), true
		}
	}
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值