前言:
在go語言中 map 是很重要的數據結構。Map 是一種無序的鍵值對的集合。Map 最重要的一點是通過 key 來快速檢索數據,key 類似於索引,指向數據的值。問題來了,這么安逸的 數據結構,它不是協程安全的 !當多個 協程同時對一個map 進行 讀寫時,會拋出致命錯誤。總結一下 想要 做到 協程安全 map 一共有以下三種方法。
1.map + 鎖
這是最常見的一種操作,當要對 map操作的時候就加鎖,其他的 協程就等待。下面是代碼示例:
package util
import "sync"
type SafeMap struct {
Data map[string]interface{}
Lock sync.RWMutex
}
func (this *SafeMap) Get(k string) interface{} {
this.Lock.RLock()
defer this.Lock.RUnlock()
if v, exit := this.Data[k]; exit {
return v
}
return nil
}
func (this *SafeMap) Set(k string, v interface{}) {
this.Lock.Lock()
defer this.Lock.Unlock()
if this.Data == nil {
this.Data = make(map[string]interface{})
}
this.Data[k] = v
}
2. sync.map
這個是go 最近版本新推出來的 協程安全 map == 可能是官方也覺得 蠻有必要的吧 。下面的代碼 主要寫一下使用方法。具體原理我就不介紹了。這里要注意一下 sync.map 不需要 初始化
var test sync.Map
//設置元素
func set (k,v interface{}){
test.Store(k,v)
}
//獲得元素
func get (k interface{}) interface{}{
tem ,exit := test.Load(k)
if exit {
return tem
}
return nil
}
//傳入一個 函數 ,sync.map 會內部迭代 ,運行這個函數
func ranggfunc (funcs func(key, value interface{}) bool) {
test.Range(funcs)
}
//刪除元素
func del(key interface{}){
test.Delete(key)
}
3.單協程操作 map ,用 channle 通信
這個思路有點 騷,就是一直由一個協程 操作map ,其他協程 通過 channle 告訴這個協程應該 怎么操作。其實這樣子 性能不是很好,因為 channle 底層 也是鎖 ,而且 map 存數據 是要 計算hash的 ,之前是 多個協程自己算自己的hash ,現在變成了一個協程計算了。但是這個思路還是可以,不僅僅是 在 map上可以這么操作。socket 通信啊, 全局 唯一對象的調用啊,都可以用此思路。下面給大家看一下我是實現的代碼:
package main
import (
"fmt"
//"time"
)
var (
ADD interface{} = 1
DEL interface{} = 2
GET interface{} = 3
)
type safeMap struct {
Msq chan *[3] interface{} //['type','id','value',channle]
data map[interface{}]interface{}
chanl chan interface{}
}
func NewSafeMap() *safeMap {
tem := &safeMap{}
tem.init()
return tem
}
func (this *safeMap) init() {
this.Msq = make(chan *[3]interface{},10)
this.data = make(map[interface{}]interface{})
this.chanl = make(chan interface{},0)
go this.run()
}
func (this *safeMap) run() {
for {
select {
case msg := <- this.Msq :
switch msg[0] {
case ADD :
this.dataAdd(msg[1],msg[2])
case DEL :
this.dataDel(msg[1])
case GET :
this.dataGet(msg[1])
}
}
}
}
func (this *safeMap) msqChan (typ,id,val interface{}) *[3]interface{}{
return &[...]interface{}{typ,id,val}
}
//保存 或者更新元素
func (this *safeMap) dataAdd (id , value interface{}) {
this.data[id] = value
}
//刪除元素
func (this *safeMap) dataDel (id interface{}) {
delete(this.data,id)
}
//獲得元素
func (this *safeMap) dataGet (id interface{}) {
if val ,exit := this.data[id] ;exit {
this.chanl <- val
return
}
this.chanl <- nil
}
//----------------------------------------------------對外接口--------------------------------
func (this *safeMap) Add (id ,value interface{}) {
this.Msq <- this.msqChan(ADD,id,value)
}
func (this *safeMap) Del (id interface{}) {
this.Msq <- this.msqChan(DEL,id ,nil)
}
func (this *safeMap) Get (id interface{}) interface{} {
this.Msq <- this.msqChan(GET,id,nil)
res := <- this.chanl
return res
}
//獲得 長度
func (this *safeMap) GetLength() uint32{
return uint32(len(this.data))
}
func main() {
sa := NewSafeMap()
// sa.Add(1,1)
sa.Add(2,3)
fmt.Println(2,sa.Get(2))
sa.Del(2)
fmt.Println(2,sa.Get(2))
}
