golang线程安全的map实现

时间:2021-05-22

网上找的协程安全的map都是用互斥锁或者读写锁实现的,这里用单个协程来实现下,即所有的增删查改操作都集成到一个goroutine中,这样肯定不会出现多线程并发访问的问题。

基本思路是后台启动一个长期运行的goroutine,阻塞的接受自己channel中的请求req,req分为不同的请求,比如读key,写key等,然后在这个goroutine中进行各种操作。

例: Get方法向readSig(channel)中发送一条请求。请求是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 safemapfunc 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 mapfunc (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 mapfunc (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 mapfunc (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 mapfunc (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 mapfunc (s *smap) Exists(key interface{}) bool { if _,found := s.Get(key); found { return true } return false}

github地址:https://github.com/hackssssss/safemap

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。

声明:本页内容来源网络,仅供用户参考;我单位不保证亦不表示资料全面及准确无误,也不保证亦不表示这些资料为最新信息,如因任何原因,本网内容或者用户因倚赖本网内容造成任何损失或损害,我单位将不会负任何法律责任。如涉及版权问题,请提交至online#300.cn邮箱联系删除。

相关文章