golang线程安全的map实现
程序员文章站
2022-03-06 09:06:20
网上找的协程安全的map都是用互斥锁或者读写锁实现的,这里用单个协程来实现下,即所有的增删查改操作都集成到一个goroutine中,这样肯定不会出现多线程并发访问的问题。...
网上找的协程安全的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 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地址:
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。