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
})
}
为了进一步明确并发安全字段中键值的实际类型,有两种方案:
前一种方案在扩展性方面有所欠缺,后一种方案通常会影响程序的性能。
sync.Map 中的 read 与 dirty 互换:
第一种方案:
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
})
}
第二种方案:
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
})
}