go語言協程安全map

前言:

在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 不須要 初始化socket

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))
}
相關文章
相關標籤/搜索