go---并发安全字典 sync.Map

自制的简易并发安全字典

package main

import (
	"fmt"
	"sync"
)

// 自制的简易并发安全字典
type ConcurrentMap struct {
	m	map[interface{}]interface{}
	mu	sync.RWMutex
}

func NewConcurrentMap() *ConcurrentMap {
	return &ConcurrentMap {
		m: make(map[interface{}]interface{}),
	}
}

func (cMap *ConcurrentMap) Delete (key interface{}) {
	cMap.mu.Lock()
	defer cMap.mu.Unlock()
	delete(cMap.m, key)
}

func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) {
	cMap.mu.RLock()
	defer cMap.mu.RUnlock()
	value, ok = cMap.m[key]
	return
}

func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
	cMap.mu.Lock()
	defer cMap.mu.Unlock()
	actual, loaded = cMap.m[key]
	if loaded {
		return
	}
	cMap.m[key] = value
	actual = value
	return
}

func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) {
	cMap.mu.RLock()
	defer cMap.mu.RUnlock()
	for k, v := range cMap.m {
		if !f(k, v) {
			break
		}
	}
}

func (cMap *ConcurrentMap) Store(key, value interface{}) {
	cMap.mu.Lock()	
	defer cMap.mu.Unlock()
	cMap.m[key] = value
}

func main() {
	pairs := []struct {
		k int
		v string
	} {
		{k: 1, v: "a"},
		{k: 2, v: "b"},
		{k: 3, v: "c"},
		{k: 4, v: "d"},
	}
	
	cMap := NewConcurrentMap()
	cMap.Store(pairs[0].k, pairs[0].v)
	cMap.Store(pairs[1].k, pairs[1].v)
	cMap.Store(pairs[2].k, pairs[2].v)
	fmt.Println("[Three pairs have been stored in the ConcurrentMap instancel]")

	cMap.Range(func(key, value interface{}) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})

	k0 := pairs[0].k
	v0, ok := cMap.Load(k0)
	fmt.Printf("The result of Load: %v, %v (key: %v)\n", v0, ok, k0)

	k2, v2 := pairs[2].k, pairs[2].v
	actual2, loaded2 := cMap.LoadOrStore(k2,v2)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 
		actual2, loaded2, k2, v2)
	
	k1 := pairs[1].k
	cMap.Delete(k1)
	fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance]\n", k1)
	v1, ok := cMap.Load(k1)
	v1 = pairs[1].v
	actual1, loaded1 := cMap.LoadOrStore(k1, v1)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n",
		actual1, loaded1, k1, v1)

	cMap.Range(func(key, value interface{}) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})	
}

go---并发安全字典 sync.Map_第1张图片

sync.Map

为了进一步明确并发安全字段中键值的实际类型,有两种方案:

  • 在编码时就完全确定键和值的类型,然后利用 Go 语言的编译器检查。
  • 接受动态的类型设置,并在程序运行时通过反射操作进行检查。

前一种方案在扩展性方面有所欠缺,后一种方案通常会影响程序的性能。

sync.Map 中的 read 与 dirty 字段:
go---并发安全字典 sync.Map_第2张图片

sync.Map 中的 read 与 dirty 互换:go---并发安全字典 sync.Map_第3张图片
第一种方案:

package main

import (
	"fmt"
	"sync"
)

// 键类型为 int、值类型为 string 的并发安全字典
type IntStrMap struct {
	m sync.Map
}

func (iMap *IntStrMap) Delete(key int) {
	iMap.m.Delete(key)
}

func (iMap *IntStrMap) Load(key int) (value string, ok bool) {
	v, ok := iMap.m.Load(key)
	if v != nil {
		value = v.(string)
	}
	return
}

func (iMap *IntStrMap) LoadOrStore(key int, value string) (actual string, loaded bool) {
	a, loaded := iMap.m.LoadOrStore(key, value)
	actual = a.(string)
	return
}

func (iMap *IntStrMap) Range(f func(key int, value string) bool) {
	f1 := func(key, value interface{}) bool {
		return f(key.(int), value.(string))
	}
	iMap.m.Range(f1)
}

func (iMap *IntStrMap) Store(key int, value string) {
	iMap.m.Store(key, value)
}

func main() {
	pairs := []struct {
		k int
		v string
	} {
		{k: 1, v: "a"},
		{k: 2, v: "b"},
		{k: 3, v: "c"},
		{k: 4, v: "d"},
	}
	
	var iMap IntStrMap
	iMap.Store(pairs[0].k, pairs[0].v)
	iMap.Store(pairs[1].k, pairs[1].v)
	iMap.Store(pairs[2].k, pairs[2].v)
	fmt.Println("[Three pairs have been stored in the IntStrMap instancel]")

	iMap.Range(func(key int, value string) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})

	k0 := pairs[0].k
	v0, ok := iMap.Load(k0)
	fmt.Printf("The result of Load: %v, %v (key: %v)\n", v0, ok, k0)

	k2, v2 := pairs[2].k, pairs[2].v
	actual2, loaded2 := iMap.LoadOrStore(k2,v2)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 
		actual2, loaded2, k2, v2)
	
	k1 := pairs[1].k
	iMap.Delete(k1)
	fmt.Printf("[The pair with the key of %v has been removed from the IntStrMap instance]\n", k1)
	v1, ok := iMap.Load(k1)
	v1 = pairs[1].v
	actual1, loaded1 := iMap.LoadOrStore(k1, v1)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n",
		actual1, loaded1, k1, v1)

	iMap.Range(func(key int, value string) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})	
}

go---并发安全字典 sync.Map_第4张图片

第二种方案:

package main

import (
	"fmt"
	"sync"
	"errors"
	"reflect"
)

// 键类型为 int、值类型为 string 的并发安全字典
type ConcurrentMap struct {
	m		sync.Map
	keyType		reflect.Type
	valueType	reflect.Type
}

func NewConcurrentMap(keyType, valueType reflect.Type) (*ConcurrentMap, 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 := &ConcurrentMap {
		keyType:	keyType,
		valueType: valueType,
	}
	return cMap, nil
}

func (cMap *ConcurrentMap) Delete(key interface{}) {
	if reflect.TypeOf(key) != cMap.keyType {
		return
	}
	cMap.m.Delete(key)
}

func (cMap *ConcurrentMap) Load(key interface{}) (value interface{}, ok bool) {
	if reflect.TypeOf(key) != cMap.keyType {
		return
	}
	return cMap.m.Load(key)
}

func (cMap *ConcurrentMap) LoadOrStore(key, value interface{}) (actual interface{}, loaded bool) {
	if reflect.TypeOf(key) != cMap.keyType {
		panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key)))
	}
	if reflect.TypeOf(value) != cMap.valueType{
		panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value)))
	}
	actual, loaded = cMap.m.LoadOrStore(key, value)
	return
}

func (cMap *ConcurrentMap) Range(f func(key, value interface{}) bool) {
	cMap.m.Range(f)
}

func (cMap *ConcurrentMap) Store(key, value interface{}) {
	if reflect.TypeOf(key) != cMap.keyType {
		panic(fmt.Errorf("wrong key type: %v", reflect.TypeOf(key)))
	}
	if reflect.TypeOf(value) != cMap.valueType{
		panic(fmt.Errorf("wrong value type: %v", reflect.TypeOf(value)))
	}
	cMap.m.Store(key, value)
}

func main() {
	pairs := []struct {
		k int
		v string
	} {
		{k: 1, v: "a"},
		{k: 2, v: "b"},
		{k: 3, v: "c"},
		{k: 4, v: "d"},
	}
	
	cMap, err := NewConcurrentMap(
		reflect.TypeOf(pairs[0].k), reflect.TypeOf(pairs[0].v))
	if err != nil {
		fmt.Printf("fatal error: %s", err)
		return
	}
	cMap.Store(pairs[0].k, pairs[0].v)
	cMap.Store(pairs[1].k, pairs[1].v)
	cMap.Store(pairs[2].k, pairs[2].v)
	fmt.Println("[Three pairs have been stored in the ConcurrentMap instancel]")

	cMap.Range(func(key, value interface{}) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})

	k0 := pairs[0].k
	v0, ok := cMap.Load(k0)
	fmt.Printf("The result of Load: %v, %v (key: %v)\n", v0, ok, k0)

	k2, v2 := pairs[2].k, pairs[2].v
	actual2, loaded2 := cMap.LoadOrStore(k2,v2)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n", 
		actual2, loaded2, k2, v2)
	
	k1 := pairs[1].k
	cMap.Delete(k1)
	fmt.Printf("[The pair with the key of %v has been removed from the ConcurrentMap instance]\n", k1)
	v1, ok := cMap.Load(k1)
	v1 = pairs[1].v
	actual1, loaded1 := cMap.LoadOrStore(k1, v1)
	fmt.Printf("The result of LoadOrStore: %v, %v (key: %v, value: %v)\n",
		actual1, loaded1, k1, v1)

	cMap.Range(func(key, value interface{}) bool {
		fmt.Printf("The result of an iteration in Range: %v, %v\n", key, value)
		return true
	})	
}

go---并发安全字典 sync.Map_第5张图片

你可能感兴趣的:(Go语言核心36讲(郝林)笔记)