golang線程安全的map實現(xiàn)
網(wǎng)上找的協(xié)程安全的map都是用互斥鎖或者讀寫鎖實現(xiàn)的,這里用單個協(xié)程來實現(xiàn)下,即所有的增刪查改操作都集成到一個goroutine中,這樣肯定不會出現(xiàn)多線程并發(fā)訪問的問題。
基本思路是后臺啟動一個長期運行的goroutine,阻塞的接受自己channel中的請求req,req分為不同的請求,比如讀key,寫key等,然后在這個goroutine中進行各種操作。
例: Get方法向readSig(channel)中發(fā)送一條請求。請求是readReq的指針,當run方法接收到信號時,讀取底層map,將值寫入readReq的value中(value是個channel),Get方法阻塞的接收value,接收到就返回value。
ps:花了兩個多小時寫完,只是簡單的做了測試,沒有深入測試,另外性能也沒有測過,以后有空會深入測試一下正確性以及相比加鎖的寫法其性能如何。
package util
type smap struct {
m map[interface{}]interface{}
readSig chan *readReq
writeSig chan *writeReq
lenSig chan *lenReq
terminateSig chan bool
delSig chan *delReq
scanSig chan *scanReq
}
type readReq struct {
key interface{}
value interface{}
ok chan bool
}
type writeReq struct {
key interface{}
value interface{}
ok chan bool
}
type lenReq struct {
len chan int
}
type delReq struct {
key interface{}
ok chan bool
}
type scanReq struct {
do func(interface{}, interface{})
doWithBreak func(interface{}, interface{}) bool
brea int
done chan bool
}
// NewSmap returns an instance of the pointer of safemap
func NewSmap() *smap {
var mp smap
mp.m = make(map[interface{}]interface{})
mp.readSig = make(chan *readReq)
mp.writeSig = make(chan *writeReq)
mp.lenSig = make(chan *lenReq)
mp.delSig = make(chan *delReq)
mp.scanSig = make(chan *scanReq)
go mp.run()
return &mp
}
//background function to operate map in one goroutine
//this can ensure that the map is Concurrent security.
func (s *smap) run() {
for {
select {
case read := <-s.readSig:
if value, ok := s.m[read.key]; ok {
read.value = value
read.ok <- true
} else {
read.ok <- false
}
case write := <-s.writeSig:
s.m[write.key] = write.value
write.ok <- true
case l := <-s.lenSig:
l.len <- len(s.m)
case sc := <-s.scanSig:
if sc.brea == 0 {
for k, v := range s.m {
sc.do(k, v)
}
} else {
for k, v := range s.m {
ret := sc.doWithBreak(k, v)
if ret {
break
}
}
}
sc.done <- true
case d := <-s.delSig:
delete(s.m, d.key)
d.ok <- true
case <-s.terminateSig:
return
}
}
}
//Get returns the value of key which provided.
//if the key not found in map, ok will be false.
func (s *smap) Get(key interface{}) (interface{}, bool) {
req := &readReq{
key: key,
ok: make(chan bool),
}
s.readSig <- req
ok := <-req.ok
return req.value, ok
}
//Set set the key and value to map
//ok returns true indicates that key and value is successfully added to map
func (s *smap) Set(key interface{}, value interface{}) bool {
req := &writeReq{
key: key,
value: value,
ok: make(chan bool),
}
s.writeSig <- req
return <-req.ok //TODO 暫時先是同步的,異步的可能存在使用方面的問題。
}
//Clear clears all the key and value in map.
func (s *smap) Clear() {
s.m = make(map[interface{}]interface{})
}
//Size returns the size of map.
func (s *smap) Size() int {
req := &lenReq{
len: make(chan int),
}
s.lenSig <- req
return <-req.len
}
//terminate s.Run function. this function is usually called for debug.
//after this do NOT use smap again, because it can make your program block.
func (s *smap) TerminateBackGoroutine() {
s.terminateSig <- true
}
//Del delete the key in map
func (s *smap) Del(key interface{}) bool {
req := &delReq{
key: key,
ok: make(chan bool),
}
s.delSig <- req
return <-req.ok
}
//scan the map. do is a function which operate all of the key and value in map
func (s *smap) EachItem(do func(interface{}, interface{})) {
req := &scanReq{
do: do,
brea: 0,
done: make(chan bool),
}
s.scanSig <- req
<-req.done
}
//scan the map util function 'do' returns true. do is a function which operate all of the key and value in map
func (s *smap) EachItemBreak(do func(interface{}, interface{}) bool, condition bool) {
req := &scanReq{
doWithBreak: do,
brea: 1,
done: make(chan bool),
}
s.scanSig <- req
<-req.done
}
//Exists checks whether the key which provided is exists in map
func (s *smap) Exists(key interface{}) bool {
if _,found := s.Get(key); found {
return true
}
return false
}
github地址:https://github.com/hackssssss/safemap
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Go語言實現(xiàn)廣播式并發(fā)聊天服務(wù)器
本文主要介紹了Go語言實現(xiàn)廣播式并發(fā)聊天服務(wù)器,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習或者工作具有一定的參考學(xué)習價值,需要的朋友們下面隨著小編來一起學(xué)習學(xué)習吧2024-08-08
go語言中切片與內(nèi)存復(fù)制 memcpy 的實現(xiàn)操作
這篇文章主要介紹了go語言中切片與內(nèi)存復(fù)制 memcpy 的實現(xiàn)操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04
Go1.16新特性embed打包靜態(tài)資源文件實現(xiàn)
這篇文章主要為大家介紹了Go?1.16新特性embed打包靜態(tài)資源文件的實現(xiàn)示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪2022-07-07
Golang中println和fmt.Println區(qū)別解析
Golang 中打印數(shù)據(jù)通常使用 fmt.Println() 方法,也可以使用內(nèi)置的 println() 方法。這兩個方法大家可能都使用過,它們的區(qū)別是什么呢?本文給大家詳細講解,感興趣的朋友跟隨小編一起看看吧2023-03-03
Mac下Vs code配置Go語言環(huán)境的詳細過程
這篇文章給大家介紹Mac下Vs code配置Go語言環(huán)境的詳細過程,本文給大家介紹的非常詳細,對大家的學(xué)習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2021-07-07

