go语言sync.Map学习

  • go语言早期的Map并不是并发安全的,在1.9版本才加入的sync.Map
  • sync.Map的键和值都是interface{},所以可以存储任何类型的数据。不过与Map一样,键的类型不能是函数,字典和切片类型,这是因为程序需要在编译期间对键值进行检查,不正确的键值类型会panic
  • 在日常使用时可以对sync.Map进行包装,显示的指定map的键类型。
 func (strmap *StrSyncMap)load(key string)(value interface{},ok bool)  {
	load, ok := strmap.m.Load(key)
	if load != nil {
		value = load.(string)
	}
	return
 }
 func (strMap *StrSyncMap)Store( key string, value interface{})  {
	strMap.m.Store(key,value)
 }
 func (strMap *StrSyncMap)LoadOrStore(key string,value interface{}) (actual interface{},loaded bool) {
	store, loaded := strMap.m.LoadOrStore(key, value)
	if store != nil {
		actual = store.(string)
	}
	return
 }
 func (strMap *StrSyncMap)Range(f func(key string,value interface{}) bool)  {
	f1:= func(key , value interface{}) bool {
		return f(key.(string),value)
	}
	strMap.m.Range(f1)
 }
 func (strMap *StrSyncMap)delete(key string)  {
	strMap.m.Delete(key)
 }
  • 也可以使用第二种方式
type CustomMap struct{
    map sync.Map
    keyType reflect.Type
    value   reflect.Type
}
func NewCustomMap(keyType, valueType reflect.Type) (*CustomMap, error) {
   if keyType == nil {
   	return nil, errors.New("nil key type")
   }
   if !keyType.Comparable() {
   	return nil, fmt.Errorf("incomparable key type: %s", keyType)
   }
   if valueType == nil {
   	return nil, errors.New("nil value type")
   }
   cMap := &CustomMap{
   	keyType:   keyType,
   	valueType: valueType,
   }
   return cMap, nil
}
//在查找和使用的时候判断类型即可。
  • sync.Map解析
    1. sync.Map在内部使用了大量的原子操作来存储数据,最大程度减少锁都使用。
    2. sync.Map内部有一个read字段,是atomic.Value类型,也就是interface{}类型。它相当于一个快照,在条件满足时,会保存sync.Map中的所有数据,不会增减,但会被允许修改键所对应的值。它先把值转换为了unsafe.Pointer类型的值,然后再把后者封装,并储存在其中的原生字典中。如此一来,在变更某个键所对应的值的时候,就也可以使用原子操作了。
    3. sync.Map中的另一个原生字典由它的dirty字段代表。 它存储键值对的方式与read字段中的原生字典一致,它的键类型也是interface{},并且同样是把值先做转换和封装后再进行储存的。
    4. sync.Map在查找指定的键所对应的值的时候,总会先去只读字典中寻找,并不需要锁定互斥锁。只有当确定“只读字典中没有,但脏字典中可能会有这个键”的时候,它才会在锁的保护下去访问脏字典。相对应的,sync.Map在存储键值对的时候,只要只读字典中已存有这个键,并且该键值对未被标记为“已删除”,就会把新值存到里面并直接返回,这种情况下也不需要用到锁。如果没有会在锁的保护下将键值存储到脏字典当中。
    5. 只读字典和脏字典之间是会互相转换的。在脏字典中查找键值对次数足够多的时候,sync.Map会把脏字典直接作为只读字典,保存在它的read字段中,然后把代表脏字典的dirty字段的值置为nil。
posted @ 2021-04-19 22:00  月下繁星杨  阅读(463)  评论(0编辑  收藏  举报